15

I'm trying to make my template function produce a compile-time error if the non-specialized base version is instantiated. I tried the usual compile-time assert pattern (negative array size) but the compile is failing even when the template is not instantiated. Any thoughts on how to to make it fail if and only if the base-template function is instantiated?

template<class Foo> void func(Foo x) {
  // I want the compiler to complain only if this function is instantiated.
  // Instead, the compiler is complaining here at the declaration.
  int Must_Use_Specialization[-1];
}

template<> void func(int x) {
  printf("Hi\n");
}
drwowe
  • 1,975
  • 1
  • 15
  • 17
  • A good example of the need for a template function is required and a function overload is inadequate is when the template parameter defines the return type. (You cannot overload a function on return type.) `template T readFileAs(std::string const& fileName);` More often, this would be returned as a collection of `T`. – Jeff Benshetler Aug 20 '19 at 14:31

5 Answers5

21

Not defining it is the easiest solution:

template<class Foo> void func(Foo x);

template<> void func(int x) {
  printf("Hi\n");
}

You can also define them in CPP files and use this which will work.

And static assert method:

template<class Foo> void func(Foo x) {
  static_assert(sizeof(Foo) != sizeof(Foo), "func must be specialized for this type!");
}
Community
  • 1
  • 1
Pubby
  • 51,882
  • 13
  • 139
  • 180
8

In C++11 you can use static_assert like this:

template<typename T> struct fake_dependency: public std::false_type {};
template<class Foo> void func(Foo x) {
   static_assert(fake_dependency<Foo>::value, "must use specialization");
}

The fake_dependency struct is necessary to make the assert dependent on your template parameter, so it waits with the evaluation, till the template is instantiated. You can similarly fix your solution like this:

template<class> struct fake_dependency { enum {value = -1 }; };

template<class Foo> void func(Foo x) {
    int Must_Use_Specialization[fake_dependency<Foo>::value];
}

See also here for a live demo.

Grizzly
  • 19,595
  • 4
  • 60
  • 78
  • That works. I also thought of another solutions that works: referencing a non-existant member, so the base function becomes: template void func(Foo x) { x.You_must_call_a_specialization_of_this_function; } – drwowe Jan 13 '12 at 17:21
  • @user1148117: Given an infinite number of potential classes, it is hard to guarantee some Foo won't have this member :) – UncleBens Jan 13 '12 at 17:35
  • Another way to create a dependecy on a template argument without having to create an additional type is to use `static_assert(sizeof(T) == 0, "...");`. This works since the standard specifies that every type (even empty structs) have a size of at least 1. Note that some compilers allow 0-length types in form of a language extension (e.g. GCC's ["Structures With No Members"](https://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Empty-Structures.html)). – Max Truxa Feb 26 '15 at 10:15
5

You have to make it dependent on Foo, like this:

int Must_Use_Specialization[-sizeof(Foo)];
jpalecek
  • 47,058
  • 7
  • 102
  • 144
3

You don't need the base template if you are never going to use it! Just provide overloads for the types you do want to use!

void func(int x) {
    printf("Hi 1\n");
}

void func(double x) {
    printf("Hi 2\n");
}

void func(Bar x) {
    printf("Hi 3\n");
}

This will get you a compile time error for func(foo); (unless foo is convertible to one of the other types).

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

Just use Boost.StaticAssert

(Edit: or static_assert if you have C++11 support. I forgot about that).

Useless
  • 64,155
  • 6
  • 88
  • 132