Reputation: 6437
Is it possible to get a compile-time error if and only if the default specialization of a templated variable gets instantiated? For example
template<typename T>
constexpr int foo = /* Something that fails */;
template<>
constexpr int foo<bool> = 42;
// ...
int bar = foo<bool>; // All good!
int meow = foo<int>; // Error if and only if this line exists
All I've tried putting in /* Something that fails*/
has ended up failing even if the specialization isn't instantiated. Is this possible? Even better if the error can somehow be reported through a mechanism like static_assert
so that it is at least somewhat legible.
Upvotes: 2
Views: 90
Reputation: 138051
You should ask a language lawyer if this is standard. Clang will not let you leave a templated constexpr variable undefined, but it will let you reference undefined template instantiations from a constexpr initializer. You can then write this:
template<typename T>
struct no_such_type_for_foo;
template<typename T>
constexpr int foo = no_such_type_for_foo<T>::value;
template<>
constexpr int foo<int> = 4;
int main()
{
int y = foo<int>; // all good
int z = foo<bool>; // implicit instantiation of undefined template 'no_such_type_for_foo<bool>'
}
Upvotes: 4
Reputation: 6437
Based on zneak and Sam's solutions, I came up with a variant that allows a custom error message through static_assert
. The key is that the static_assert
condition needs to depend on the template argument, or it will be evaluated immediately whether or not the template is actually used.
The problem is that we want the static_assert
to unconditionally fail, and so the condition should reduce to false
for every possible argument. We are relying on the compiler not making that analysis itself (I'm not sure whether it would actually be allowed to figure it out if the template is not instantiated).
template<typename T>
constexpr int no_such_type_for_foo()
{
static_assert(sizeof(T) < 0, "No such type for foo");
return 0;
}
template<typename T>
constexpr int foo = no_such_type_for_foo<T>();
template<>
constexpr int foo<bool> = 42;
int main()
{
int y = foo<bool>; // all good
int z = foo<int>; // static_assert failed "No such type for foo"
}
Upvotes: 0
Reputation: 118340
gcc
doesn't like the static
keyword in the template instantiation.
But just leaving the default template undefined appears to do the trick:
template<typename T>
constexpr int foo;
template<>
constexpr int foo<bool> = 42;
With that, this works:
std::cout << foo<bool> << std::endl;
and this fails:
std::cout << foo<char> << std::endl;
with:
t.C:2:15: error: uninitialized const ‘foo<char>’ [-fpermissive]
constexpr int foo;
^
I don't see much difference between this situation, and a more common situation where the default template is not defined:
template<typename T> class foo;
template<>
class foo<char> {
// ...
};
Same thing.
Upvotes: 1