Reputation: 1437
The idea behind the following code is to enable the class only for types with certain sizes, like 1 in the following example:
#include <assert.h>
template<typename T>
class X
{
private:
template<int S=sizeof(T)>
inline void foo(void) {static_assert(false,"illegal type");}
};
template<typename T> template<int S>
inline void X<T>::foo<1>(void){};
int main()
{
X<char> x;
return 0;
}
However this doesn't compile in gcc, which fails with the following error message:
q.cpp: In member function ‘void X<T>::foo()’:
q.cpp:9:26: error: static assertion failed: illegal type
inline void foo(void) {static_assert(false,"illegal type");}
^~~~~~~~~~~~~
q.cpp: At global scope:
q.cpp:14:30: error: non-class, non-variable partial specialization ‘foo<1>’ is not allowed
inline void X<T>::foo<1>(void){};
^
q.cpp:14:13: error: redefinition of ‘void X<T>::foo()’
inline void X<T>::foo<1>(void){};
^~~~
q.cpp:9:15: note: ‘void X<T>::foo()’ previously declared here
inline void foo(void) {static_assert(false,"illegal type");}
What would be the right syntax to define foo to achieve the desired results?
Upvotes: 0
Views: 44
Reputation: 119099
Your code has a few issues.
A template for which no valid specialization can be generated makes the program ill-formed, even if the template is never instantiated ([temp.res]/8.1). This implies that static_assert(false, "illegal type")
can never be part of a well-formed program; you must make the condition dependent on a template parameter.
It is not possible to declare an explicit (full) specialization for a member of an unspecialized class template ([temp.expl.spec]/16), which is what you're trying to do with X<T>::foo
.
Even if not for the above, if you changed the static_assert
condition to S == 1
, it couldn't prevent the enclosing class template from being instantiated because (a) instantiating a class template doesn't automatically instantiate the definitions of its member functions, and (b) providing default arguments for all template parameters doesn't automatically cause the template to be instantiated with those default arguments. The instantiation would only occur if you called x.foo()
or did something else requiring the definition to exist.
Instead of this song and dance, it's better to put the static_assert
directly in the class:
template<typename T>
class X {
static_assert(sizeof(T) == 1, "illegal type");
// ...
};
It's legal to put static_assert
there because static_assert
is a declaration, not an expression.
Upvotes: 1
Reputation: 48938
Your version fails because static_assert(false)
is always false and the compiler can diagnose it early on. The common trick here is to make the condition depend on a template parameter and to trick the compiler into thinking it can't evaluate the condition, but in your case, you can do this easier:
template<typename T>
class X
{
static_assert(sizeof(T) == 1, "illegal type");
};
Now as you can see, the condition clearly depends on T
and so the compiler will only diagnose the static_assert
when instantiating X
with a specific T
, which is exactly what you want.
Upvotes: 3