简体   繁体   中英

static_assert in function template with non-type template parameter

I have a function template with integer template parameter. I would like to provide an implementation for particular integers only. An attempt to use the function template with another argument should cause a compilation error.

I used static_assert in a way presented below.

#include <type_traits>
#include <iostream>

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

template <int T>
void function() {
    static_assert(false_type<decltype(T)>::value, "Error");
};

template <>
void function<1>() {
    std::cout << 1 << std::endl;
}

int main() {
    function<1>();
}

The code works nicely until gcc 9.1 where it gives an error: static assertion failed .

I would like to know if there is a technique that would allow to ahieve my goal and that is compatible with gcc 9.1 ?

A static_assert whose first argument is a non-dependent false constant is always "ill-formed, no diagnostic required", even in a template that is never instantiated. (So neither g++ nor clang++ is "incorrect" here.) In your function template, T is value-dependent but not type-dependent (its type is always int ), so decltype(T) is not dependent, and neither is false_type<int>::value .

Could you have your false_type simply also take an int as parameter?

#include <type_traits>
#include <iostream>

template <int>
struct false_type : public std::false_type {};

template <int T>
void function() {
    static_assert(false_type<T>::value, "Error");
};

template <>
void function<1>() {
    std::cout << 1 << std::endl;
}

int main() {
     function<1>();
}

GCC 9.1 seems to recognize that false_type<decltype(T)>::value doesn't really depend on T , which lets it evaluate the condition early (when first seeing the template, rather than on an instantination).

Here is a workaround:

template <auto V, auto...> inline constexpr auto dependent_value = V;

template <int T>
void function()
{
    static_assert(dependent_value<false, T>, "Error");
}

This way the compiler has to instantinate function<T> to evaluate dependent_value<false, T> (since dependent_value could have been specialized after the definition of function<T> ).


Note that since no valid instantination can be generated for your implementation of function<int T> , the code in your question is ill-formed, no diagnostic required .

This workaround doesn't have this problem, since you could make a valid instantination of function<int T> by specializing dependent_value first.


There's also a simpler solution that doesn't involve static_assert :

template <int T> void function() = delete;

I didn't understand what the problem was with the original code when I first answered this, but now, thanks to the other respondents, I do, so it was all worth it.

Anyway, one obvious solution would be to replace your three templates with:

template <int T>
void function() {
    static_assert(T == 1, "Error");
};

which works fine in gcc .

clang and MSVC still compile the original code successfully, by the way.

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