使用非类型参数的部分模板专业化:GCC与MSVS

时间:2017-02-09 17:10:11

标签: c++ gcc visual-c++ language-lawyer template-specialization

考虑这个简单的模板专业化:

template<typename T, size_t I>
struct S {};

template<typename T>
struct S<T, std::tuple_size<T>::value> {};

GCC不编译它,因为它在模板参数T中使用模板参数std::tuple_size<T>::value

  

错误:模板参数'std :: tuple_size&lt; _Tp&gt; :: value'   涉及模板参数

现在让我们用T模板参数中的typename std::remove_reference<T>::type替换tuple_size

// Using primary structure template from previous example.
template<typename T>
struct S<T, std::tuple_size<typename std::remove_reference<T>::type>::value> {};

此代码仍在模板参数中使用模板参数,但GCC会编译它而不会出现任何错误或警告。为什么呢?

现在,如果我们尝试使用带有/std:c++latest标志的MSVS编译第二个示例,它会因错误C2755而停止:

  

部分特化的非类型参数必须简单   标识符

这个奇怪的限制是什么?我想在I变得等于元组大小时停止编译时递归。​​

那么他们中谁错了:MSVS或GCC?

请注意,即使没有任何模板实例化,MSVS也会报告错误,而GCC适用于所有这些实例:

S<std::tuple<int, float>, 9> s1;
S<std::tuple<int, float>, 2> s2;
S<int, 42> s3;

我使用MSVS Community 2015 Update 3及其默认编译器和GCC 6.2.1。

Tried Clang 3.8.0。它不会编译两个片段,其错误类似于GCC的消息:

  

错误:非类型模板参数取决于模板参数   部分专业化

1 个答案:

答案 0 :(得分:3)

在过去几年中,处理部分类模板专业化可行性的标准的特定部分已经改变了很多次。原始限制[temp.class.spec.match]读取:

  

部分专用的非类型参数表达式不应涉及部分特化的模板参数,除非参数表达式是简单的标识符

您的代码明显与此相反,std::tuple_size<T>::value不是标识符。

然后在cwg issue 1315后更改为:

  

每个模板参数在非推断的上下文之外的 template-id 中至少出现一次。

但我们可以在那里 - T在非演绎的上下文中用作第一个模板参数。在template auto之后,它现在显示为:

  

如果由于其结构而无法推断出部分特化的模板参数    template-parameter-list template-id ,程序格式不正确。

但我们也可以。可以推断,你有正确的结构&#34; - 您的专业化是在与主要相同的位置使用非类型模板参数,它们应匹配正常。

我认为遵循1315的决议(我认为 post -C ++ 14),代码应该是格式良好的,但gcc和clang都拒绝它。一个不幸的解决方法是使用两个类型的参数:

template <class T, class I>
struct S;

template<typename T>
struct S<T, typename std::tuple_size<T>::type> {};

template <size_t I>
using size_ = std::integral_constant<size_t, I>;

int main() {
    S<std::tuple<int>, size_<1>> s;
}

gcc和clang都接受了那一个。

相关问题