static_assert 在具有非类型模板参数的函数模板中

static_assert in function template with non-type template parameter

我有一个带有整数模板参数的函数模板。我只想提供特定整数的实现。尝试将函数模板与另一个参数一起使用会导致编译错误。

我按照下面介绍的方式使用 static_assert

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

代码在 gcc 9.1 之前运行良好,它给出了 error: static assertion failed.

我想知道是否有一种技术可以实现我的目标并且与 gcc 9.1 兼容?

我第一次回答这个问题时不明白原始代码有什么问题,但现在,感谢其他回答者,我明白了,所以这一切都是值得的。

无论如何,一个明显的解决方案是将您的三个模板替换为:

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

哪个works fine in gcc.

clang 和 MSVC 仍然成功编译了原始代码。

GCC 9.1 似乎认识到 false_type<decltype(T)>::value 并不真正依赖于 T,这让它可以及早评估条件(当第一次看到模板时,而不是在实例化时)。

这是一个解决方法:

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

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

这样编译器必须实例化 function<T> 来评估 dependent_value<false, T>(因为 dependent_value 可以在 之后专门化 [的定义=14=]).


请注意,由于无法为您的 function<int T> 实现生成有效的实例化,因此您问题中的代码是 ill-formed, no diagnostic required

此变通方法没有此问题,因为您可以通过首先特化 dependent_value 来有效实例化 function<int T>


还有一个更简单的解决方案,不涉及 static_assert:

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

第一个参数是 non-dependent 假常量的 static_assert 始终是 "ill-formed, no diagnostic required",即使在从未实例化的模板中也是如此。 (所以这里 g++ 和 clang++ 都不是 "incorrect"。)在你的函数模板中,T 是 value-dependent 但不是 type-dependent (它的类型总是 int),所以 decltype(T) 不依赖,false_type<int>::value.

也不依赖

能否让您的 false_type 也简单地使用 int 作为参数?

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