简体   繁体   中英

How can I make a templated variable specialization fail at compile time if instantiated?

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.

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>'
}

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.

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"
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM