问题
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