具有非类型模板参数的功能模板中的static_assert

时间:2019-07-19 22:52:54

标签: c++ templates template-specialization static-assert

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

我以下面介绍的方式使用了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兼容?

3 个答案:

答案 0 :(得分:4)

一个static_assert的第一个参数是不相关的虚假常量,即使在从未实例化的模板中,也始终“格式错误,无需诊断”。 (因此,这里的g ++和clang ++都不是“不正确的”。)在您的函数模板中,T与值相关,但与类型无关(其类型始终为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>();
}

答案 1 :(得分:2)

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可以在function<T>的定义之后


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

此解决方法不存在此问题,因为您可以通过先专门设置function<int T>来制作dependent_value的有效实例。


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

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

答案 2 :(得分:1)

当我第一次回答这个问题时,我不明白原始代码是什么问题,但是现在,由于其他答复者,我做到了,所以这一切都值得。

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

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

其中works fine in gcc

clang和MSVC仍然可以成功地编译原始代码。