diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs
index ba78cc876eb6e154212dccbd1ba7a1f86d39bdfd..74bf4c9a2016b4fbff12e8c2dc338364b555be6b 100644
--- a/src/bindgen/bindings.rs
+++ b/src/bindgen/bindings.rs
@@ -89,13 +89,10 @@ impl Bindings {
         out.new_line();
 
         if self.config.language == Language::Cxx {
-            out.new_line_if_not_start();
-            out.write("extern \"C\" {");
-            out.new_line();
-
             self.open_namespaces(&mut out);
         }
 
+
         for constant in &self.constants {
             out.new_line_if_not_start();
             constant.write(&self.config, &mut out);
@@ -123,6 +120,12 @@ impl Bindings {
             out.new_line();
         }
 
+        if self.config.language == Language::Cxx {
+            out.new_line_if_not_start();
+            out.write("extern \"C\" {");
+            out.new_line();
+        }
+
         for global in &self.globals {
             out.new_line_if_not_start();
             global.write(&self.config, &mut out);
diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs
index 697fd5b7f475cbcd24ede00a6f800ede12a92a6b..222285fa5ce663cf19b49eb2dc3b246f650876be 100644
--- a/src/bindgen/cdecl.rs
+++ b/src/bindgen/cdecl.rs
@@ -5,7 +5,7 @@
 use std::io::Write;
 
 use bindgen::ir::{Function, Type};
-use bindgen::writer::SourceWriter;
+use bindgen::writer::{ListType, SourceWriter};
 
 // This code is for translating Rust types into C declarations.
 // See Section 6.7, Declarations, in the C standard for background.
@@ -30,6 +30,7 @@ impl CDeclarator {
 struct CDecl {
     type_qualifers: String,
     type_name: String,
+    type_generic_args: Vec<Type>,
     declarators: Vec<CDeclarator>
 }
 
@@ -38,6 +39,7 @@ impl CDecl {
         CDecl {
             type_qualifers: String::new(),
             type_name: String::new(),
+            type_generic_args: Vec::new(),
             declarators: Vec::new(),
         }
     }
@@ -62,10 +64,6 @@ impl CDecl {
     fn build_type(&mut self, t: &Type, is_const: bool) {
         match t {
             &Type::Path(ref path) => {
-                // We should be assured that there are no generics by instantiating
-                // monomorphs and mangling paths.
-                assert!(path.generics.len() == 0);
-
                 if is_const {
                     assert!(self.type_qualifers.len() == 0);
                     self.type_qualifers = "const".to_owned();
@@ -73,6 +71,8 @@ impl CDecl {
 
                 assert!(self.type_name.len() == 0);
                 self.type_name = path.name.clone();
+                assert!(self.type_generic_args.len() == 0);
+                self.type_generic_args = path.generics.clone();
             }
             &Type::Primitive(ref p) => {
                 if is_const {
@@ -114,6 +114,12 @@ impl CDecl {
             write!(out, "{}", self.type_name);
         };
 
+        if !self.type_generic_args.is_empty() {
+            out.write("<");
+            out.write_horizontal_source_list(&self.type_generic_args, ListType::Join(", "));
+            out.write(">");
+        }
+
         // When we have an identifier, put a space between the type and the declarators
         if ident.is_some() {
             out.write(" ");
diff --git a/src/bindgen/ir/generics.rs b/src/bindgen/ir/generics.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2e3ff92f5d37fac957f3276dc605752143884830
--- /dev/null
+++ b/src/bindgen/ir/generics.rs
@@ -0,0 +1,48 @@
+use std::ops::Deref;
+use std::io::Write;
+
+use syn;
+
+use bindgen::config::{Config, Language};
+use bindgen::writer::{Source, SourceWriter};
+
+#[derive(Default, Debug, Clone)]
+pub struct GenericParams(pub Vec<String>);
+
+impl GenericParams {
+    pub fn new(generics: &syn::Generics) -> Self {
+        GenericParams(
+            generics
+                .ty_params
+                .iter()
+                .map(|x| x.ident.to_string())
+                .collect::<Vec<_>>(),
+        )
+    }
+}
+
+impl Deref for GenericParams {
+    type Target = [String];
+
+    fn deref(&self) -> &[String] {
+        &self.0
+    }
+}
+
+impl Source for GenericParams {
+    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
+        if !self.0.is_empty() {
+            if config.language == Language::Cxx {
+                out.write("template<");
+                for (i, item) in self.0.iter().enumerate() {
+                    if i != 0 {
+                        out.write(", ");
+                    }
+                    write!(out, "typename {}", item);
+                }
+                out.write(">");
+                out.new_line();
+            }
+        }
+    }
+}
diff --git a/src/bindgen/ir/mod.rs b/src/bindgen/ir/mod.rs
index 96c915c2392b8e403c2d0e5a9e75b152a3711c52..1f2e3cca86c91ff46bc2ee23c96a281ec13d81be 100644
--- a/src/bindgen/ir/mod.rs
+++ b/src/bindgen/ir/mod.rs
@@ -7,6 +7,7 @@ pub mod cfg;
 pub mod constant;
 pub mod enumeration;
 pub mod function;
+pub mod generics;
 pub mod global;
 pub mod item;
 pub mod opaque;
@@ -24,6 +25,7 @@ pub use self::cfg::*;
 pub use self::constant::*;
 pub use self::enumeration::*;
 pub use self::function::*;
+pub use self::generics::*;
 pub use self::global::*;
 pub use self::item::*;
 pub use self::opaque::*;
diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs
index bf391ad785ceac4fda95eded6836c729c58cbe3d..3d460e76979f37ad5463bc6ac3b38062feab6236 100644
--- a/src/bindgen/ir/opaque.rs
+++ b/src/bindgen/ir/opaque.rs
@@ -8,7 +8,7 @@ use syn;
 
 use bindgen::config::{Config, Language};
 use bindgen::dependencies::Dependencies;
-use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, ItemContainer, Item, Path, Specialization, Type};
+use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, ItemContainer, Item, Path, Specialization, Type};
 use bindgen::library::Library;
 use bindgen::mangle;
 use bindgen::monomorph::Monomorphs;
@@ -17,7 +17,7 @@ use bindgen::writer::{Source, SourceWriter};
 #[derive(Debug, Clone)]
 pub struct OpaqueItem {
     pub name: Path,
-    pub generic_params: Vec<String>,
+    pub generic_params: GenericParams,
     pub cfg: Option<Cfg>,
     pub annotations: AnnotationSet,
     pub documentation: Documentation,
@@ -28,13 +28,9 @@ impl OpaqueItem {
                generics: &syn::Generics,
                attrs: &Vec<syn::Attribute>,
                mod_cfg: &Option<Cfg>) -> OpaqueItem {
-        let generic_params = generics.ty_params.iter()
-                                               .map(|x| x.ident.to_string())
-                                               .collect::<Vec<_>>();
-
         OpaqueItem {
             name: name,
-            generic_params: generic_params,
+            generic_params: GenericParams::new(generics),
             cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
             annotations: AnnotationSet::load(attrs).unwrap_or(AnnotationSet::new()),
             documentation: Documentation::load(attrs),
@@ -46,7 +42,7 @@ impl OpaqueItem {
 
         let monomorph = OpaqueItem {
             name: mangle::mangle_path(&self.name, generic_values),
-            generic_params: vec![],
+            generic_params: GenericParams::default(),
             cfg: self.cfg.clone(),
             annotations: self.annotations.clone(),
             documentation: self.documentation.clone(),
@@ -102,6 +98,8 @@ impl Source for OpaqueItem {
 
         self.documentation.write(config, out);
 
+        self.generic_params.write(config, out);
+
         if config.language == Language::C {
             write!(out, "typedef struct {} {};", self.name, self.name);
         } else {
diff --git a/src/bindgen/ir/specialization.rs b/src/bindgen/ir/specialization.rs
index 6e581e985196dbc007de2be0a62a081af9404f81..3f109d2432e5bfda94723b55a9a8e3f9498cd964 100644
--- a/src/bindgen/ir/specialization.rs
+++ b/src/bindgen/ir/specialization.rs
@@ -6,7 +6,7 @@ use syn;
 
 use bindgen::dependencies::Dependencies;
 use bindgen::ir::{AnnotationSet, Cfg, Documentation};
-use bindgen::ir::{GenericPath, ItemContainer, Item, PrimitiveType};
+use bindgen::ir::{GenericParams, GenericPath, ItemContainer, Item, PrimitiveType};
 use bindgen::library::Library;
 
 /// A type alias that generates a copy of its aliasee with a new name. If the type
@@ -15,7 +15,7 @@ use bindgen::library::Library;
 #[derive(Debug, Clone)]
 pub struct Specialization {
     pub name: String,
-    pub generic_params: Vec<String>,
+    pub generic_params: GenericParams,
     pub aliased: GenericPath,
     pub cfg: Option<Cfg>,
     pub annotations: AnnotationSet,
@@ -31,10 +31,6 @@ impl Specialization {
     {
         match ty {
             &syn::Ty::Path(ref _q, ref p) => {
-                let generic_params = generics.ty_params.iter()
-                                                       .map(|x| x.ident.to_string())
-                                                       .collect::<Vec<_>>();
-
                 let path = GenericPath::load(p)?;
 
                 if PrimitiveType::maybe(&path.name).is_some() {
@@ -43,7 +39,7 @@ impl Specialization {
 
                 Ok(Specialization {
                     name: name,
-                    generic_params: generic_params,
+                    generic_params: GenericParams::new(generics),
                     aliased: path,
                     cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
                     annotations: AnnotationSet::load(attrs)?,
diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs
index 693f5e83bf54f89ebec3ed22bd99424378128b21..deb8c7d65f3e515ef23bc0d56d8b8ea7211ffd19 100644
--- a/src/bindgen/ir/structure.rs
+++ b/src/bindgen/ir/structure.rs
@@ -8,7 +8,7 @@ use syn;
 
 use bindgen::config::{Config, Language};
 use bindgen::dependencies::Dependencies;
-use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, ItemContainer, Item, Repr, Specialization, Type};
+use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, ItemContainer, Item, Repr, Specialization, Type};
 use bindgen::library::Library;
 use bindgen::mangle;
 use bindgen::monomorph::Monomorphs;
@@ -19,7 +19,7 @@ use bindgen::writer::{ListType, Source, SourceWriter};
 #[derive(Debug, Clone)]
 pub struct Struct {
     pub name: String,
-    pub generic_params: Vec<String>,
+    pub generic_params: GenericParams,
     pub fields: Vec<(String, Type, Documentation)>,
     pub tuple_struct: bool,
     pub cfg: Option<Cfg>,
@@ -60,13 +60,9 @@ impl Struct {
             }
         };
 
-        let generic_params = generics.ty_params.iter()
-                                               .map(|x| x.ident.to_string())
-                                               .collect::<Vec<_>>();
-
         Ok(Struct {
             name: name,
-            generic_params: generic_params,
+            generic_params: GenericParams::new(generics),
             fields: fields,
             tuple_struct: tuple_struct,
             cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
@@ -173,7 +169,7 @@ impl Item for Struct {
 
         let monomorph = Struct {
             name: mangle::mangle_path(&self.name, generic_values),
-            generic_params: vec![],
+            generic_params: GenericParams::default(),
             fields: self.fields.iter()
                                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                                .collect(),
@@ -215,12 +211,12 @@ impl Item for Struct {
 
 impl Source for Struct {
     fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
-        assert!(self.generic_params.is_empty());
-
         self.cfg.write_before(config, out);
 
         self.documentation.write(config, out);
 
+        self.generic_params.write(config, out);
+
         if config.language == Language::C {
             out.write("typedef struct");
         } else {
@@ -257,7 +253,7 @@ impl Source for Struct {
                 write!(out, "bool operator{}(const {}& {}) const", op, self.name, other);
                 out.open_brace();
                 out.write("return ");
-                out.write_vertical_list(&self.fields.iter()
+                out.write_vertical_source_list(&self.fields.iter()
                                                     .map(|x| format!("{} {} {}.{}", x.0, op, other, x.0))
                                                     .collect(),
                                         ListType::Join(&format!(" {}", conjuc)));
diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs
index c406280828dd8c3e34788ec202827294f26e85b0..82b6c4d10d1897a4e84d6f824647a2df4f4ec3bc 100644
--- a/src/bindgen/ir/ty.rs
+++ b/src/bindgen/ir/ty.rs
@@ -10,7 +10,7 @@ use syn;
 use bindgen::cdecl;
 use bindgen::config::Config;
 use bindgen::dependencies::Dependencies;
-use bindgen::ir::{Documentation, GenericPath, ItemContainer, Item, Path};
+use bindgen::ir::{Documentation, GenericParams, GenericPath, ItemContainer, Item, Path};
 use bindgen::library::Library;
 use bindgen::monomorph::Monomorphs;
 use bindgen::utilities::IterHelpers;
@@ -357,7 +357,7 @@ impl Type {
         }
     }
 
-    pub fn add_dependencies_ignoring_generics(&self, generic_params: &Vec<String>, library: &Library, out: &mut Dependencies) {
+    pub fn add_dependencies_ignoring_generics(&self, generic_params: &GenericParams, library: &Library, out: &mut Dependencies) {
         match self {
             &Type::ConstPtr(ref ty) => {
                 ty.add_dependencies_ignoring_generics(generic_params, library, out);
@@ -400,7 +400,7 @@ impl Type {
     }
 
     pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
-        self.add_dependencies_ignoring_generics(&Vec::new(), library, out)
+        self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out)
     }
 
     pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
@@ -517,6 +517,12 @@ impl Type {
     }
 }
 
+impl Source for String {
+    fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
+        write!(out, "{}", self);
+    }
+}
+
 impl Source for Type {
     fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
         cdecl::write_type(out, &self);
diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs
index a7a1efdffb0642fc2d607aa878b604781f6c59e7..1429ea7009c3cb369ece805f6b5a5eb3ccf3924c 100644
--- a/src/bindgen/ir/union.rs
+++ b/src/bindgen/ir/union.rs
@@ -8,7 +8,7 @@ use syn;
 
 use bindgen::config::{Config, Language};
 use bindgen::dependencies::Dependencies;
-use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, ItemContainer, Item, Repr, Specialization, Type};
+use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, ItemContainer, Item, Repr, Specialization, Type};
 use bindgen::ir::SynFieldHelpers;
 use bindgen::library::Library;
 use bindgen::mangle;
@@ -20,7 +20,7 @@ use bindgen::writer::{ListType, Source, SourceWriter};
 #[derive(Debug, Clone)]
 pub struct Union {
     pub name: String,
-    pub generic_params: Vec<String>,
+    pub generic_params: GenericParams,
     pub fields: Vec<(String, Type, Documentation)>,
     pub tuple_union: bool,
     pub cfg: Option<Cfg>,
@@ -61,13 +61,9 @@ impl Union {
             }
         };
 
-        let generic_params = generics.ty_params.iter()
-                                               .map(|x| x.ident.to_string())
-                                               .collect::<Vec<_>>();
-
         Ok(Union {
             name: name,
-            generic_params: generic_params,
+            generic_params: GenericParams::new(generics),
             fields: fields,
             tuple_union: tuple_union,
             cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
@@ -174,7 +170,7 @@ impl Item for Union {
 
         let monomorph = Union {
             name: mangle::mangle_path(&self.name, generic_values),
-            generic_params: vec![],
+            generic_params: GenericParams::default(),
             fields: self.fields.iter()
                                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                                .collect(),
@@ -216,12 +212,12 @@ impl Item for Union {
 
 impl Source for Union {
     fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
-        assert!(self.generic_params.is_empty());
-
         self.cfg.write_before(config, out);
 
         self.documentation.write(config, out);
 
+        self.generic_params.write(config, out);
+
         if config.language == Language::C {
             out.write("typedef union");
         } else {
diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs
index dc91ea8c0ad633b6f8e18440ea5e5a6549b623fd..3e8a60d1c04ec3a884f72b3d9eb5f2dc13e859f9 100644
--- a/src/bindgen/library.rs
+++ b/src/bindgen/library.rs
@@ -60,7 +60,10 @@ impl Library {
         self.rename_items();
         self.specialize_items();
         self.simplify_option_to_ptr();
-        self.instantiate_monomorphs();
+
+        if self.config.language == Language::C {
+            self.instantiate_monomorphs();
+        }
 
         let mut dependencies = Dependencies::new();
 
diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs
index f965b643c7af01e6c09e14eab3896e06bf2e9cac..93e44516c070bc34cafe68143091139214596c30 100644
--- a/src/bindgen/parser.rs
+++ b/src/bindgen/parser.rs
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
 use syn;
 
 use bindgen::cargo::{Cargo, PackageRef};
-use bindgen::ir::{AnnotationSet, Cfg, Constant, Documentation, Enum, Function};
+use bindgen::ir::{AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams};
 use bindgen::ir::{ItemMap, OpaqueItem, Specialization, Static, Struct, Typedef, Union};
 use bindgen::utilities::{SynAbiHelpers, SynItemHelpers};
 
@@ -371,9 +371,11 @@ impl Parse {
         let mut add_opaque = |name: &str, generic_params: Vec<&str>| {
             self.opaque_items.try_insert(OpaqueItem {
                 name: name.to_owned(),
-                generic_params: generic_params.iter()
-                                              .map(|x| (*x).to_owned())
-                                              .collect(),
+                generic_params: GenericParams(
+                    generic_params.iter()
+                                  .map(|x| (*x).to_owned())
+                                  .collect()
+                ),
                 cfg: None,
                 annotations: AnnotationSet::new(),
                 documentation: Documentation::none(),
diff --git a/src/bindgen/writer.rs b/src/bindgen/writer.rs
index d460fde2788ed03c6fd42ab7f423b64ba6d439d9..74267d1da2dbc3fe58677f0a1ee2c95def26f7b8 100644
--- a/src/bindgen/writer.rs
+++ b/src/bindgen/writer.rs
@@ -193,30 +193,6 @@ impl<'a, F: Write> SourceWriter<'a, F> {
         }
     }
 
-    pub fn write_vertical_list<'b>(&mut self, items: &Vec<String>, list_type: ListType<'b>) {
-        let align_length = self.line_length_for_align();
-        self.push_set_spaces(align_length);
-        for (i, item) in items.iter().enumerate() {
-            write!(self, "{}", item);
-
-            match list_type {
-                ListType::Join(text) => {
-                    if i != items.len() - 1 {
-                        write!(self, "{}", text);
-                    }
-                }
-                ListType::Cap(text) => {
-                    write!(self, "{}", text);
-                }
-            }
-
-            if i != items.len() - 1 {
-                self.new_line();
-            }
-        }
-        self.pop_tab();
-    }
-
     pub fn write_vertical_source_list<'b, S: Source>(&mut self, items: &Vec<S>, list_type: ListType<'b>) {
         let align_length = self.line_length_for_align();
         self.push_set_spaces(align_length);
diff --git a/tests/expectations/alias.cpp b/tests/expectations/alias.cpp
index 63848e548456ed930f21b1ba9305fb67bfe9c365..d770f0ce454af19c92c4c33e69fc3bf435774a45 100644
--- a/tests/expectations/alias.cpp
+++ b/tests/expectations/alias.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 enum class Status : uint32_t {
   Ok = 0,
   Err = 1,
@@ -13,39 +11,23 @@ struct Dep {
   float b;
 };
 
-struct Foo_i32 {
-  int32_t a;
-  int32_t b;
+template<typename X>
+struct Foo {
+  X a;
+  X b;
   Dep c;
 };
 
-typedef Foo_i32 IntFoo;
+typedef Foo<int32_t> IntFoo;
 
-struct Foo_f64 {
-  double a;
-  double b;
-  Dep c;
-};
-
-typedef Foo_f64 DoubleFoo;
+typedef Foo<double> DoubleFoo;
 
 typedef int32_t Unit;
 
 typedef Status SpecialStatus;
 
+extern "C" {
+
 void root(IntFoo x, DoubleFoo y, Unit z, SpecialStatus w);
 
 } // extern "C"
-
-template<typename X>
-struct Foo;
-
-template<>
-struct Foo<double> : public Foo_f64 {
-
-};
-
-template<>
-struct Foo<int32_t> : public Foo_i32 {
-
-};
diff --git a/tests/expectations/annotation.cpp b/tests/expectations/annotation.cpp
index 011549738f32cb459c5d2af5ff10047056bc6e1c..0e272ce9ac77bf2dc8871ed6b3af15e3ccc725dd 100644
--- a/tests/expectations/annotation.cpp
+++ b/tests/expectations/annotation.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 enum class C : uint32_t {
   X = 2,
   Y = 3,
@@ -24,6 +22,8 @@ struct B {
   float y;
 };
 
+extern "C" {
+
 void root(A x, B y, C z);
 
 } // extern "C"
diff --git a/tests/expectations/cdecl.cpp b/tests/expectations/cdecl.cpp
index ffdc54fa2c0cea3959d35dc474598a9bab15bb58..dd8c4215169ca4c09dc955bd0ff43a2ce836f0c7 100644
--- a/tests/expectations/cdecl.cpp
+++ b/tests/expectations/cdecl.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 typedef void (*A)();
 
 typedef void (*B)();
@@ -31,6 +29,8 @@ typedef bool (*M[16])(int32_t, int32_t);
 
 typedef void (*N[16])(int32_t, int32_t);
 
+extern "C" {
+
 void (*O())();
 
 void root(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n);
diff --git a/tests/expectations/cfg-2.cpp b/tests/expectations/cfg-2.cpp
index 44b493f303bb06de314fe39f684a7f6082607026..9b54c4e78196294d3b4f7d391ff70f7aa0e92c6f 100644
--- a/tests/expectations/cfg-2.cpp
+++ b/tests/expectations/cfg-2.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 #if (defined(NOT_DEFINED) || defined(DEFINED))
 struct Foo {
   int32_t x;
@@ -25,6 +23,8 @@ struct Root {
   Bar w;
 };
 
+extern "C" {
+
 void root(Root a);
 
 } // extern "C"
diff --git a/tests/expectations/cfg.cpp b/tests/expectations/cfg.cpp
index c21480e3d2644c3e3c7b22321ebb01d64139cc9b..4500055ee11de673bc94ab979b64925f1a9c34d3 100644
--- a/tests/expectations/cfg.cpp
+++ b/tests/expectations/cfg.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 #if (defined(PLATFORM_WIN) || defined(M_32))
 enum class BarType : uint32_t {
   A = 0,
@@ -35,6 +33,8 @@ struct BarHandle {
 };
 #endif
 
+extern "C" {
+
 #if (defined(PLATFORM_UNIX) && defined(X11))
 void root(FooHandle a);
 #endif
diff --git a/tests/expectations/constant.cpp b/tests/expectations/constant.cpp
index 988bc3563a3ab36eed1823d4317c8faef9449ba1..df09abdacbfae8d21269c775a8bace45418c28c5 100644
--- a/tests/expectations/constant.cpp
+++ b/tests/expectations/constant.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 static const int32_t FOO = 10;
 
 static const float ZOM = 3.14;
@@ -11,6 +9,8 @@ struct Foo {
   int32_t x[FOO];
 };
 
+extern "C" {
+
 void root(Foo x);
 
 } // extern "C"
diff --git a/tests/expectations/enum.cpp b/tests/expectations/enum.cpp
index a51af59680088932e77a19629303fef087bf88e4..1537c3c359a93be164614ee751cc050f287a2e0e 100644
--- a/tests/expectations/enum.cpp
+++ b/tests/expectations/enum.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 enum class A : uint32_t {
   a1 = 0,
   a2 = 2,
@@ -40,6 +38,8 @@ enum class E : intptr_t {
 
 struct Opaque;
 
+extern "C" {
+
 void root(Opaque *o, A a, B b, C c, D d, E e);
 
 } // extern "C"
diff --git a/tests/expectations/euclid.cpp b/tests/expectations/euclid.cpp
index 56e65d1c799058bf61a6d6605793ed7395f3eb59..7fd0d9a6fa282481557d4a3de41307210b7a3364 100644
--- a/tests/expectations/euclid.cpp
+++ b/tests/expectations/euclid.cpp
@@ -1,257 +1,115 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct LayoutUnit;
 
 struct UnknownUnit;
 
-struct TypedLength_f32__UnknownUnit {
-  float _0;
-};
-
-struct TypedLength_f32__LayoutUnit {
-  float _0;
+template<typename T, typename Unit>
+struct TypedLength {
+  T _0;
 };
 
-struct Length_f32 {
-  float _0;
+template<typename T>
+struct Length {
+  T _0;
 };
 
-typedef TypedLength_f32__LayoutUnit LayoutLength;
+typedef TypedLength<float, LayoutUnit> LayoutLength;
 
-struct TypedSideOffsets2D_f32__UnknownUnit {
-  float top;
-  float right;
-  float bottom;
-  float left;
-};
-
-struct TypedSideOffsets2D_f32__LayoutUnit {
-  float top;
-  float right;
-  float bottom;
-  float left;
+template<typename T, typename U>
+struct TypedSideOffsets2D {
+  T top;
+  T right;
+  T bottom;
+  T left;
 };
 
-struct SideOffsets2D_f32 {
-  float top;
-  float right;
-  float bottom;
-  float left;
+template<typename T>
+struct SideOffsets2D {
+  T top;
+  T right;
+  T bottom;
+  T left;
 };
 
-typedef TypedSideOffsets2D_f32__LayoutUnit LayoutSideOffsets2D;
+typedef TypedSideOffsets2D<float, LayoutUnit> LayoutSideOffsets2D;
 
-struct TypedSize2D_f32__UnknownUnit {
-  float width;
-  float height;
-};
-
-struct TypedSize2D_f32__LayoutUnit {
-  float width;
-  float height;
+template<typename T, typename U>
+struct TypedSize2D {
+  T width;
+  T height;
 };
 
-struct Size2D_f32 {
-  float width;
-  float height;
+template<typename T>
+struct Size2D {
+  T width;
+  T height;
 };
 
-typedef TypedSize2D_f32__LayoutUnit LayoutSize2D;
-
-struct TypedPoint2D_f32__UnknownUnit {
-  float x;
-  float y;
-};
+typedef TypedSize2D<float, LayoutUnit> LayoutSize2D;
 
-struct TypedPoint2D_f32__LayoutUnit {
-  float x;
-  float y;
+template<typename T, typename U>
+struct TypedPoint2D {
+  T x;
+  T y;
 };
 
-struct Point2D_f32 {
-  float x;
-  float y;
+template<typename T>
+struct Point2D {
+  T x;
+  T y;
 };
 
-typedef TypedPoint2D_f32__LayoutUnit LayoutPoint2D;
-
-struct TypedRect_f32__UnknownUnit {
-  TypedPoint2D_f32__UnknownUnit origin;
-  TypedSize2D_f32__UnknownUnit size;
-};
+typedef TypedPoint2D<float, LayoutUnit> LayoutPoint2D;
 
-struct TypedRect_f32__LayoutUnit {
-  TypedPoint2D_f32__LayoutUnit origin;
-  TypedSize2D_f32__LayoutUnit size;
+template<typename T, typename U>
+struct TypedRect {
+  TypedPoint2D<T, U> origin;
+  TypedSize2D<T, U> size;
 };
 
-struct Rect_f32 {
-  TypedPoint2D_f32__UnknownUnit origin;
-  TypedSize2D_f32__UnknownUnit size;
+template<typename T>
+struct Rect {
+  TypedPoint2D<T, UnknownUnit> origin;
+  TypedSize2D<T, UnknownUnit> size;
 };
 
-typedef TypedRect_f32__LayoutUnit LayoutRect;
+typedef TypedRect<float, LayoutUnit> LayoutRect;
 
-struct TypedTransform2D_f32__UnknownUnit__LayoutUnit {
-  float m11;
-  float m12;
-  float m21;
-  float m22;
-  float m31;
-  float m32;
+template<typename T, typename Src, typename Dst>
+struct TypedTransform2D {
+  T m11;
+  T m12;
+  T m21;
+  T m22;
+  T m31;
+  T m32;
 };
 
-struct TypedTransform2D_f32__LayoutUnit__UnknownUnit {
-  float m11;
-  float m12;
-  float m21;
-  float m22;
-  float m31;
-  float m32;
-};
+extern "C" {
 
-void root(TypedLength_f32__UnknownUnit length_a,
-          TypedLength_f32__LayoutUnit length_b,
-          Length_f32 length_c,
+void root(TypedLength<float, UnknownUnit> length_a,
+          TypedLength<float, LayoutUnit> length_b,
+          Length<float> length_c,
           LayoutLength length_d,
-          TypedSideOffsets2D_f32__UnknownUnit side_offsets_a,
-          TypedSideOffsets2D_f32__LayoutUnit side_offsets_b,
-          SideOffsets2D_f32 side_offsets_c,
+          TypedSideOffsets2D<float, UnknownUnit> side_offsets_a,
+          TypedSideOffsets2D<float, LayoutUnit> side_offsets_b,
+          SideOffsets2D<float> side_offsets_c,
           LayoutSideOffsets2D side_offsets_d,
-          TypedSize2D_f32__UnknownUnit size_a,
-          TypedSize2D_f32__LayoutUnit size_b,
-          Size2D_f32 size_c,
+          TypedSize2D<float, UnknownUnit> size_a,
+          TypedSize2D<float, LayoutUnit> size_b,
+          Size2D<float> size_c,
           LayoutSize2D size_d,
-          TypedPoint2D_f32__UnknownUnit point_a,
-          TypedPoint2D_f32__LayoutUnit point_b,
-          Point2D_f32 point_c,
+          TypedPoint2D<float, UnknownUnit> point_a,
+          TypedPoint2D<float, LayoutUnit> point_b,
+          Point2D<float> point_c,
           LayoutPoint2D point_d,
-          TypedRect_f32__UnknownUnit rect_a,
-          TypedRect_f32__LayoutUnit rect_b,
-          Rect_f32 rect_c,
+          TypedRect<float, UnknownUnit> rect_a,
+          TypedRect<float, LayoutUnit> rect_b,
+          Rect<float> rect_c,
           LayoutRect rect_d,
-          TypedTransform2D_f32__UnknownUnit__LayoutUnit transform_a,
-          TypedTransform2D_f32__LayoutUnit__UnknownUnit transform_b);
+          TypedTransform2D<float, UnknownUnit, LayoutUnit> transform_a,
+          TypedTransform2D<float, LayoutUnit, UnknownUnit> transform_b);
 
 } // extern "C"
-
-template<typename T>
-struct Length;
-
-template<>
-struct Length<float> : public Length_f32 {
-
-};
-
-template<typename T>
-struct Point2D;
-
-template<>
-struct Point2D<float> : public Point2D_f32 {
-
-};
-
-template<typename T>
-struct Rect;
-
-template<>
-struct Rect<float> : public Rect_f32 {
-
-};
-
-template<typename T>
-struct SideOffsets2D;
-
-template<>
-struct SideOffsets2D<float> : public SideOffsets2D_f32 {
-
-};
-
-template<typename T>
-struct Size2D;
-
-template<>
-struct Size2D<float> : public Size2D_f32 {
-
-};
-
-template<typename T, typename Unit>
-struct TypedLength;
-
-template<>
-struct TypedLength<float, LayoutUnit> : public TypedLength_f32__LayoutUnit {
-
-};
-
-template<>
-struct TypedLength<float, UnknownUnit> : public TypedLength_f32__UnknownUnit {
-
-};
-
-template<typename T, typename U>
-struct TypedPoint2D;
-
-template<>
-struct TypedPoint2D<float, LayoutUnit> : public TypedPoint2D_f32__LayoutUnit {
-
-};
-
-template<>
-struct TypedPoint2D<float, UnknownUnit> : public TypedPoint2D_f32__UnknownUnit {
-
-};
-
-template<typename T, typename U>
-struct TypedRect;
-
-template<>
-struct TypedRect<float, LayoutUnit> : public TypedRect_f32__LayoutUnit {
-
-};
-
-template<>
-struct TypedRect<float, UnknownUnit> : public TypedRect_f32__UnknownUnit {
-
-};
-
-template<typename T, typename U>
-struct TypedSideOffsets2D;
-
-template<>
-struct TypedSideOffsets2D<float, LayoutUnit> : public TypedSideOffsets2D_f32__LayoutUnit {
-
-};
-
-template<>
-struct TypedSideOffsets2D<float, UnknownUnit> : public TypedSideOffsets2D_f32__UnknownUnit {
-
-};
-
-template<typename T, typename U>
-struct TypedSize2D;
-
-template<>
-struct TypedSize2D<float, LayoutUnit> : public TypedSize2D_f32__LayoutUnit {
-
-};
-
-template<>
-struct TypedSize2D<float, UnknownUnit> : public TypedSize2D_f32__UnknownUnit {
-
-};
-
-template<typename T, typename Src, typename Dst>
-struct TypedTransform2D;
-
-template<>
-struct TypedTransform2D<float, UnknownUnit, LayoutUnit> : public TypedTransform2D_f32__UnknownUnit__LayoutUnit {
-
-};
-
-template<>
-struct TypedTransform2D<float, LayoutUnit, UnknownUnit> : public TypedTransform2D_f32__LayoutUnit__UnknownUnit {
-
-};
diff --git a/tests/expectations/extern.cpp b/tests/expectations/extern.cpp
index cd2c8394da48347e2c0ff7d2689cb6b22128a4b9..4e974d6bd47bda90a2174d63a9c69010b724aeb4 100644
--- a/tests/expectations/extern.cpp
+++ b/tests/expectations/extern.cpp
@@ -1,13 +1,13 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Normal {
   int32_t x;
   float y;
 };
 
+extern "C" {
+
 extern void bar(Normal a);
 
 extern int32_t foo();
diff --git a/tests/expectations/fail-str.cpp b/tests/expectations/fail-str.cpp
index 735cd80e32d9eccbc1108f6bf00f8b68b48f6e63..df605c883277b83ed20674a2ed40edba126f0a62 100644
--- a/tests/expectations/fail-str.cpp
+++ b/tests/expectations/fail-str.cpp
@@ -1,12 +1,12 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Foo {
   const str *x;
 };
 
+extern "C" {
+
 void root(Foo a, const str *b);
 
 } // extern "C"
diff --git a/tests/expectations/inner_mod.cpp b/tests/expectations/inner_mod.cpp
index 233ce77e01cc78357d1fe30a372fbfb0813c460a..d09a3666dd4da1970941e4b76363ba132d806d86 100644
--- a/tests/expectations/inner_mod.cpp
+++ b/tests/expectations/inner_mod.cpp
@@ -1,12 +1,12 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Foo {
   float x;
 };
 
+extern "C" {
+
 void root(Foo a);
 
 } // extern "C"
diff --git a/tests/expectations/monomorph-1.cpp b/tests/expectations/monomorph-1.cpp
index dae1add24cd920496e6c4e2b6321b9b2d9caaf3f..ef1c47e87364a9478b54cd5e30adc1a7019b44c9 100644
--- a/tests/expectations/monomorph-1.cpp
+++ b/tests/expectations/monomorph-1.cpp
@@ -1,77 +1,35 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
-struct Bar_Bar_f32;
-
-struct Bar_Foo_f32;
-
-struct Bar_f32;
-
-struct Foo_i32 {
-  const int32_t *data;
-};
-
-struct Foo_f32 {
-  const float *data;
-};
-
-struct Foo_Bar_f32 {
-  const Bar_f32 *data;
-};
-
-struct Tuple_Foo_f32_____f32 {
-  const Foo_f32 *a;
-  const float *b;
-};
-
-struct Indirection_f32 {
-  const float *a;
-  const float *b;
-};
-
-void root(Foo_i32 a,
-          Foo_f32 b,
-          Bar_f32 c,
-          Foo_Bar_f32 d,
-          Bar_Foo_f32 e,
-          Bar_Bar_f32 f,
-          Tuple_Foo_f32_____f32 g,
-          Indirection_f32 h);
-
-} // extern "C"
-
 template<typename T>
-struct Foo;
-
-template<>
-struct Foo<int32_t> : public Foo_i32 {
-
-};
-
-template<>
-struct Foo<float> : public Foo_f32 {
+struct Bar;
 
+template<typename T>
+struct Foo {
+  const T *data;
 };
 
-template<>
-struct Foo<Bar_f32> : public Foo_Bar_f32 {
-
+template<typename T, typename E>
+struct Tuple {
+  const T *a;
+  const E *b;
 };
 
 template<typename T>
-struct Indirection;
-
-template<>
-struct Indirection<float> : public Indirection_f32 {
-
+struct Indirection {
+  const T *a;
+  const float *b;
 };
 
-template<typename T, typename E>
-struct Tuple;
+extern "C" {
 
-template<>
-struct Tuple<Foo_f32, float> : public Tuple_Foo_f32_____f32 {
+void root(Foo<int32_t> a,
+          Foo<float> b,
+          Bar<float> c,
+          Foo<Bar<float>> d,
+          Bar<Foo<float>> e,
+          Bar<Bar<float>> f,
+          Tuple<Foo<float>, float> g,
+          Indirection<float> h);
 
-};
+} // extern "C"
diff --git a/tests/expectations/monomorph-2.cpp b/tests/expectations/monomorph-2.cpp
index b458a90f28020ae7432932b5ee3cab7953c47f02..93a417558e7118b1bf87ca49ffb6f6de59b01a74 100644
--- a/tests/expectations/monomorph-2.cpp
+++ b/tests/expectations/monomorph-2.cpp
@@ -1,37 +1,20 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct A;
 
 struct B;
 
-struct List_B {
-  B *members;
+template<typename T>
+struct List {
+  T *members;
   size_t count;
 };
 
-struct List_A {
-  A *members;
-  size_t count;
-};
+extern "C" {
 
-void bar(List_B b);
+void bar(List<B> b);
 
-void foo(List_A a);
+void foo(List<A> a);
 
 } // extern "C"
-
-template<typename T>
-struct List;
-
-template<>
-struct List<B> : public List_B {
-
-};
-
-template<>
-struct List<A> : public List_A {
-
-};
diff --git a/tests/expectations/monomorph-3.cpp b/tests/expectations/monomorph-3.cpp
index e3974ffa4838c05c6f696efb18e5a76427da71b8..3a2060da8f6b6ba65eb4639ca11b55692ca8ff6c 100644
--- a/tests/expectations/monomorph-3.cpp
+++ b/tests/expectations/monomorph-3.cpp
@@ -1,43 +1,35 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
-struct Bar_Bar_f32;
-
-struct Bar_Foo_f32;
+template<typename T>
+struct Bar;
 
-struct Bar_f32;
-
-union Foo_i32 {
-  const int32_t *data;
+template<typename T>
+union Foo {
+  const T *data;
 };
 
-union Foo_f32 {
-  const float *data;
+template<typename T, typename E>
+union Tuple {
+  const T *a;
+  const E *b;
 };
 
-union Foo_Bar_f32 {
-  const Bar_f32 *data;
-};
-
-union Tuple_Foo_f32_____f32 {
-  const Foo_f32 *a;
+template<typename T>
+union Indirection {
+  const T *a;
   const float *b;
 };
 
-union Indirection_f32 {
-  const float *a;
-  const float *b;
-};
+extern "C" {
 
-void root(Foo_i32 a,
-          Foo_f32 b,
-          Bar_f32 c,
-          Foo_Bar_f32 d,
-          Bar_Foo_f32 e,
-          Bar_Bar_f32 f,
-          Tuple_Foo_f32_____f32 g,
-          Indirection_f32 h);
+void root(Foo<int32_t> a,
+          Foo<float> b,
+          Bar<float> c,
+          Foo<Bar<float>> d,
+          Bar<Foo<float>> e,
+          Bar<Bar<float>> f,
+          Tuple<Foo<float>, float> g,
+          Indirection<float> h);
 
 } // extern "C"
diff --git a/tests/expectations/simplify-option-ptr.cpp b/tests/expectations/simplify-option-ptr.cpp
index 926c56ae2ab4bfeaab5555f808bb09c7c12e7ff0..df57074465ee44f5ee89bf551d9d3b97ac2e89a2 100644
--- a/tests/expectations/simplify-option-ptr.cpp
+++ b/tests/expectations/simplify-option-ptr.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Opaque;
 
 struct Foo {
@@ -17,6 +15,8 @@ union Bar {
   void (*z)();
 };
 
+extern "C" {
+
 void root(const Opaque *a, Opaque *b, Foo c, Bar d);
 
 } // extern "C"
diff --git a/tests/expectations/static.cpp b/tests/expectations/static.cpp
index 9b92be9d1b39e79b9b39cf6229129c7a2631b87a..3a3b7e09e56c1d99355da22612f8f44396798941 100644
--- a/tests/expectations/static.cpp
+++ b/tests/expectations/static.cpp
@@ -1,14 +1,14 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Bar;
 
 struct Foo {
 
 };
 
+extern "C" {
+
 extern const Bar BAR;
 
 extern Foo FOO;
diff --git a/tests/expectations/std_lib.cpp b/tests/expectations/std_lib.cpp
index db4aae91090f261543f1ea141ed7b8aef4eb6d49..906b7041d6220e150541af8db4f92b51190ebcae 100644
--- a/tests/expectations/std_lib.cpp
+++ b/tests/expectations/std_lib.cpp
@@ -1,14 +1,19 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
+template<typename T>
+struct Option;
+
+template<typename T, typename E>
+struct Result;
 
-struct Option_i32;
+struct String;
 
-struct Result_i32__String;
+template<typename T>
+struct Vec;
 
-struct Vec_String;
+extern "C" {
 
-void root(const Vec_String *a, const Option_i32 *b, const Result_i32__String *c);
+void root(const Vec<String> *a, const Option<int32_t> *b, const Result<int32_t, String> *c);
 
 } // extern "C"
diff --git a/tests/expectations/struct.cpp b/tests/expectations/struct.cpp
index dfa6724e482b5c8df7cde882bcb55e6bd1172064..2013309be02f2f27ea053ea0507cbfa3b7851f0d 100644
--- a/tests/expectations/struct.cpp
+++ b/tests/expectations/struct.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Opaque;
 
 struct Normal {
@@ -25,6 +23,8 @@ struct TupleNamed {
   float y;
 };
 
+extern "C" {
+
 void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e);
 
 } // extern "C"
diff --git a/tests/expectations/typedef.cpp b/tests/expectations/typedef.cpp
index ca4cc789e6eac3d1a0ba36dad5fae4e648adc192..3e54bf7ec831c58897431baebe5e5cf1adf2a117 100644
--- a/tests/expectations/typedef.cpp
+++ b/tests/expectations/typedef.cpp
@@ -1,21 +1,14 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
-struct IntFoo_i32 {
+template<typename T>
+struct IntFoo {
   int32_t x;
-  int32_t y;
+  T y;
 };
 
-void root(IntFoo_i32 a);
-
-} // extern "C"
-
-template<typename T>
-struct IntFoo;
+extern "C" {
 
-template<>
-struct IntFoo<int32_t> : public IntFoo_i32 {
+void root(IntFoo<int32_t> a);
 
-};
+} // extern "C"
diff --git a/tests/expectations/union.cpp b/tests/expectations/union.cpp
index bc80bf6331566a48e5d9ef9114e596be6a75fc9e..89b19d908e9e485162e614a90813da5bb5074ef4 100644
--- a/tests/expectations/union.cpp
+++ b/tests/expectations/union.cpp
@@ -1,8 +1,6 @@
 #include <cstdint>
 #include <cstdlib>
 
-extern "C" {
-
 struct Opaque;
 
 union Normal {
@@ -15,6 +13,8 @@ union NormalWithZST {
   float y;
 };
 
+extern "C" {
+
 void root(Opaque *a, Normal b, NormalWithZST c);
 
 } // extern "C"