具有非类型参数的部分模板专业化:GCC与MSVS [英] Partial template specialization with non-type parameters: GCC vs MSVS

查看:96
本文介绍了具有非类型参数的部分模板专业化:GCC与MSVS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Consider this simple template specialization:

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

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

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

GCC does not compile it, as it uses template parameter T in the template argument std::tuple_size<T>::value:

错误:模板参数'std :: tuple_size< _Tp> :: value' 涉及模板参数

error: template argument 'std::tuple_size<_Tp>::value' involves template parameter(s)

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

Now let's replace T with typename std::remove_reference<T>::type in tuple_size template argument:

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

此代码仍在模板参数中使用模板参数,但是GCC对其进行编译而没有任何错误或警告.为什么?

This code still uses template parameter in template argument, but GCC compiles it without any errors or warnings. Why?

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

Now if we try to compile the second example using MSVS with /std:c++latest flag, it stops with error C2755:

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

non-type parameter of a partial specialization must be a simple identifier

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

What is this strange restriction? I want to stop compile-time recursion when I becomes equal to tuple size.

那么谁是错的:MSVS或GCC?

So who of them is wrong: MSVS or GCC?

请注意,即使没有任何模板实例化,MSVS也会报告错误,而GCC可以在所有这些实例中正常工作

Note that MSVS reports the error even without any template instantiations, while GCC works fine with all of these instances:

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.

I use MSVS Community 2015 Update 3 with it's default compiler and GCC 6.2.1.

尝试了Clang 3.8.0.它不会以类似于GCC消息的错误来编译两个片段:

Tried Clang 3.8.0. It does not compile both snippets with an error similar to GCC's message:

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

error: non-type template argument depends on a template parameter of the partial specialization

推荐答案

在过去的几年中,该标准中涉及局部类模板专业化可行性的特定部分已进行了很多次更改. [temp.class.spec.match]中的原始限制为:

The specific section of the standard dealing with the viability of a partial class template specialization has been changed lots of times over the last few years. The original restrictionin [temp.class.spec.match] read:

部分专用的非类型参数表达式不包含部分专用的模板参数,除非参数表达式是简单的 identifier .

您的代码显然与此不符,std::tuple_size<T>::value不是标识符.

Your code clearly runs afoul of that, std::tuple_size<T>::value is not an identifier.

然后,在 cwg问题1315 之后,内容更改为:

It then changed, after cwg issue 1315, to read:

每个 template-parameter 应该在非推论上下文之外的 template-id 中至少出现一次.

Each template-parameter shall appear at least once in the template-id outside a non-deduced context.

但是我们没关系-在非推论上下文中将T用作第一个模板参数.然后模板auto ,现在显示为:

But we're okay there - T is used in a non-deduced context as the first template parameter. And after template auto, it now reads:

如果由于其部分的结构而无法推导部分专业化的模板参数 template-parameter-list template-id ,程序格式错误.

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.

但是我们也可以.可以推论得出,您具有正确的结构"-您的专业化是在与主要对象相同的位置使用非类型模板参数,并且它们应该匹配得很好.

But we're okay there too. It can be deduced, you have the right "structure" - your specialization is using a non-type template parameter in the same location as the primary, and they should match fine.

我认为遵循1315号决议(我认为是 post -C ++ 14),代码应格式正确,但gcc和clang均拒绝使用.不幸的解决方法是改用两个 type 参数:

I think following the resolution of 1315 (which I think is post-C++14), the code should be well-formed, but both gcc and clang reject it. An unfortunate fix would be to use two type parameters instead:

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都接受那个.

Both gcc and clang accept that one.

这篇关于具有非类型参数的部分模板专业化:GCC与MSVS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆