static_assert in function template with non-type template parameter

让人想犯罪 __ 提交于 2020-02-07 05:14:06

问题


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?


回答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>();
}



回答2:


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;



回答3:


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.



来源:https://stackoverflow.com/questions/57120389/static-assert-in-function-template-with-non-type-template-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!