42

I have a templated class (call it Foo) which has several specializations. I would like the compilation to fail if someone tries to use an unspecialized version of Foo.

Here is what I actually have:

template <typename Type>
class Foo
{
  Foo() { cannot_instantiate_an_unspecialized_Foo(); }

  // This method is NEVER defined to prevent linking.
  // Its name was chosen to provide a clear explanation why the compilation failed.
  void cannot_instantiate_an_unspecialized_Foo();
};

template <>
class Foo<int>
{    };

template <>
class Foo<double>
{    };

So that:

int main()
{
  Foo<int> foo;
}

Works while:

int main()
{
  Foo<char> foo;
}

Does not.

Obviously, the compiler chain only complains when the linking process takes place. But is there a way to make it complain before ?

I can use boost.

MSalters
  • 173,980
  • 10
  • 155
  • 350
ereOn
  • 53,676
  • 39
  • 161
  • 238

3 Answers3

52

Just don't define the class:

template <typename Type>
class Foo;

template <>
class Foo<int> { };

int main(int argc, char *argv[]) 
{
    Foo<int> f; // Fine, Foo<int> exists
    Foo<char> fc; // Error, incomplete type
    return 0;
}

Why does this work? Simply because there isn't any generic template. Declared, yes, but not defined.

Seb Holzapfel
  • 3,793
  • 1
  • 19
  • 22
  • 1
    Thank you very much. I guess I was looking for something too complicated. – ereOn Aug 15 '11 at 10:51
  • @Schnommus But if you do define the class and it has a static_assert, shouldn't it never be instantiated because the specialization matches better? – David Doria Apr 22 '16 at 20:52
  • 3
    It is bad decision, because error will be issued on linking stage, not on compiling. And you will never know where exactly you used non-specialized class. – vladon Nov 24 '16 at 12:49
  • On one hand this is a simple solution but a downside is the less readable error message than what you'd have with `static_assert` as in @Luc Danton's answer. – j4x Jun 10 '22 at 12:31
24

You can simply not define the base case:

template <typename> class Foo;             // no definition!

template <> class Foo<int> { /* ... */ };  // Foo<int> is OK
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 8
    I can't believe I missed that... Thank you. Accepted Schnommus answer's because he has lower reputation. Upvoted this one for fairness. – ereOn Aug 15 '11 at 10:49
19

A trick for C++0x (also available with a C++03 static_assert emulation, but the error message isn't necessarily better than leaving the primary template undefined):

template<typename T>
struct dependent_false: std::false_type {};

template<typename Type>
struct Foo {
    static_assert( dependent_false<Type>::value
                 , "Only specializations of Foo may be used" );
};

The assertion will only trigger when Foo is instantiated with the primary template. Using static_assert( false, ... ) would trigger the assertion all the time.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • 2
    A similar trick that needs less to type is to use static_assert(sizeof(Type) == 0, "..."); As an alternative you can use BOOST_STATIC_ASSERT. I personally prefer those, as the above "don't define the base template" can lead to linker errors when you just work with references/pointers. Also often you should stop for a moment and rethink if you really need this, as templates are meant to be generic, which you are restricting here – PlasmaHH Aug 15 '11 at 15:03
  • How does this work? Wouldn't you need to define `dependent_false : std::true_type {}` for every `Specialization`, or else `dependent_false::value` would always be false? – mako Jun 23 '16 at 01:23
  • 1
    @mako It is meant to be always false. If you have e.g. a `Foo` explicit specialization defined somewhere, then it shouldn’t contain this particular assertion. So when *that* specialization is instantiated, no assertion is triggered—the primary template has no bearing on an explicit or partial specialiation. – Luc Danton Jun 23 '16 at 05:03
  • And using a template with a parameter instead of just `false` is just done to prevent static_assert from going off until someone instantiates the unspecialized template class, right? – mako Jun 23 '16 at 07:49
  • 1
    @mako That’s right. `static_assert( false );` would always trigger. If you’re interested in looking deeper into this you might want to look for dependent types and expressions (from which `dependent_false` takes its name of course). – Luc Danton Jun 23 '16 at 08:01