[C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?
-
// Foo.h enum FooKind { Bar // ~30 more kinds follow }; template<FooKind Kind> struct Foo; // Bar1.h #include "Foo.h" // keeping each specialization in separate header is very important, because some of them would include ~20 generated headers for dependencies, //each of them filled with Boost template magic to insane levels - I want to keep compile times short template<> struct Foo<Bar> { using type = int; }; // Bar1.cpp #include "Bar1.h" // Bar2.h #include "Foo.h" template<> struct Foo<Bar> { using type = float; // same argument, different type, different compilation unit }; // Bar2.cpp #include "Bar2.h"
I want this to not compile (or at least not link). Any ideas?
-
I don't think it's possible to get a compile-time error, since you want to keep the compilation units separate (although you could maybe put something together with conditional compilation...).
For link-time, you have to make sure that there's at least one method/static member that only depends on the template parameter that you're specializing. If it's a method, you need to make sure that that it's not inline. Inline methods end up as weak symbols or equivalent (if the compiler emits symbols for them at all) -- which prevents the link-time error. (At least in GCC world; I think it's similar in VS world, but you'd want to verify that.)
-
The fact that violations of the one definition rule do not necessarily cause compile-time or link-time errors has bitten me multiple times in the past. GCC will happily produce .so files which export the same symbol multiple times and let the dynamic linker play Russian roulette.
-
This post is deleted!
-
@asdf said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
The fact that violations of the one definition rule do not necessarily cause compile-time or link-time errors has bitten me multiple times in the past. GCC will happily produce .so files which export the same symbol multiple times and let the dynamic linker play Russian roulette.
Visual C++ is supposed to coalesce identical symbols in such a case.
If Gąska has control over the source, he can probably sabotage the template definition: you know you only ever want foo<bar> to be of type X, there's probably some kind of abuse of the macro preprocessor and #error pragma you can do such that if you ever try to define the class with a type other than X, it fails.
I'm not up on moderner C++ syntax; I've never seen a template definition that doesn't have the template parameter defined in the <> anyway.
-
I know this thread is roughly from the last programming century ago, but I have to ask...why not just not use templates for this? Just define separate classes and maybe use inheritance for common functionality.
-
@LB_ he is using templates!
I had another idea, one that's kind of crazy, that I don't know enough to flesh out, but the idea would be to abuse templating so that each instantiation creates something, maybe a new global class or something, such that if you try to compile it a second time you'd get a type redefinition error. That might be difficult, though, so the next best thing might be that you add one worker class, and the constructors for the template class call a method on the worker class, which is a singleton and keeps track of how many types it's been called with, and if it gets called twice, it causes a runtime error.
-
@FrostCat said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
he is using templates!
Erm…
@LB_ said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
why not just not use templates for this?
-
Hmm, that's tricky. Each translation unit is independent, so when you're compiling Bar1.cpp you're not aware of what Bar2.cpp has done or may do. There's no way to pass state along. It may be possible to break the link stage though.
So, I notice the linker doesn't like it when the same function is defined in multiple places. It may be possible to define a function that takes the type in Bar1 and Bar2 as argument, and if the same types were used, it will fail to link due to multiple definitions.
Ok, I tested it, and it seems to work. Here's my example:
// main.cpp, just here so it can build. int main() { return 0; } // test1.cpp template <class T> class MyClass {}; void MyFun(MyClass<int>){} // test2.cpp template <class T> class MyClass {}; void MyFun(MyClass<int>){}
test1.cpp and test2.cpp compile fine, but the linker will complain that
multiple definition of `MyFun(MyClass<int>)'
That should solve it.
-
@FrostCat said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
@LB_ he is using templates!
Yeah I know, but I don't understand why. This seems like exactly the time where templates should not be used.
-
@RaceProUK said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
@FrostCat said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
he is using templates!
Erm…
@LB_ said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
why not just not use templates for this?
If @blakeyrat can't be bothered to read what people write, why should I?
-
@FrostCat said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
If @blakeyrat can't be bothered to read what people write, why should I?
Because you're better than him?
-
@RaceProUK said in [C++] Some dirty trick to ensure there's only one template specialization for a given parameter, anyone?:
Because you're better than him?
Fine. I missed that one word, ok? Happy?
Unlike a lot of people I don't really have a problem with templates. I like C++. I can even write cromulent code that uses COM.
-
Would that be known as COMulent code?
-
@Scarlet_Manuka No, no it would not.