使用模板模板参数时是否需要显式列出默认参数? [英] Is it required to explicitly list default parameters when using template template parameter?

查看:716
本文介绍了使用模板模板参数时是否需要显式列出默认参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想询问以下代码示例是否应该编译:

  #include< iostream> 
#include< vector>
#include< typeinfo>

using namespace std;

template< template< class ...>类C>
struct convert_container
{
using type = C< double> ;;

// Visual Studio要求这是:
//使用type = C< double,std :: allocator< doble>>
};

int main()
{
std :: cout< typeid(convert_container< std :: vector> :: type).name();
}

代码使用GCC 4.8.1和Clang 3.4进行编译, Studio。我得到的错误:

 错误C2976:'std :: vector':模板参数太少
c :\program files(x86)\microsoft visual studio 12.0 \vc\include\vector(650):参见'std :: vector'的声明
c:\users\michał\documents \visual studio 2013 \projects\transform\transform.cpp(14):参见类模板实例化'convert_container< std :: vector>'正在编译
pre>

这个标准说的是什么?在使用模板模板参数 C 时,我需要显式声明所有参数(包括默认值),或者这只是VC ++中的一个错误?



上下文:问题来自Constructor对我上一个问题的回答: http://stackoverflow.com/a / 23874768/2617356



搜索档案时,我发现这个问题:带有模板参数(C ++)的模板中的默认值基本上是同样的问题,问题作者说,模板模板参数的默认参数必须明确说明。然而,asker接受的解决方案不适用于我的情况。

解决方案

考虑类似的问题,这个问题不在于什么是符合标准的行为,所以我认为这不是重复的。

 模板< typename = void,int = 0> struct A {}; 
template< template< typename ...>类T>结构B:T< {};
模板类B< A>

这很清楚地被标准覆盖(14.3.3p3如果你有兴趣,引用它,因为GCC和clang都已经实现规则),其中使用 A 作为 B 是不允许的,因为非类型模板参数。如果模板模板参数的实例化可以使用模板模板参数的默认模板参数,那么该规则没有意义,因此MSVC和Intel的行为比GCC和clang的行为更一致。



当然,推理如果这是有效的,标准会有不一致并不意味着它是无效的,只是它不应该是有效的。要实际检查标准的内容:


14.1模板参数[temp.param] b
$ b

10可用于模板声明或定义的默认模板参数集是通过合并来自定义的默认参数(如果在范围内)和所有的声明在范围内以相同的方式默认的函数参数是(8.3.6)。



8.3.6默认参数[dcl.fct.default] strong>



4不同作用域中的声明具有完全不同的默认参数集。也就是说,内部作用域中的声明不会从外部作用域的声明中获取默认参数,反之亦然。


解决这个使用默认模板参数,我认为它设法这样做。 Nikos Athanasiou已经包含了标准的一部分,说任何默认的模板参数 C 可以使用:


14.1模板参数[temp.param]



模板模板参数允许具有默认的模板参数。当指定这样的默认参数时,它们适用于模板模板参数范围内的模板模板参数




由于使用了 C 的默认模板参数, std :: vector 不是,MSVC和Intel似乎在这里是正确的。



并且想出一个清楚地表明不能考虑GCC和clang的例子符合这里:

 模板< typename = char,typename = short> 
struct A {};

template< template< typename = void,typename ...>类T>
struct B {
using type = T<>
};

GCC和clang都处理 B< A> :: type T 使用一个默认模板参数,而另一个从作为 code> A ,即使标准不允许在不同范围的声明中合并默认参数(因此默认模板参数)。






为了避免需要输入allocator参数,您可以使用模板别名:



<$> p $ p> template< template< class ...>类C>
struct convert_container
{
using type = C< double> ;;
};

template< typename T>
using vector_default_alloc = std :: vector< T> ;;

int main()
{
std :: cout< typeid(convert_container< vector_default_alloc> :: type).name();
}



我现在不能在MSVC上测试,但是英特尔接受它,没有理由说明此变体无效。


I'd like to ask whether the following code sample should compile:

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

template <template <class...> class C>
struct convert_container
{
    using type = C<double>; 

    // Visual Studio requires this to be:
    // using type = C<double, std::allocator<doble>>
};

int main()
{
    std::cout << typeid(convert_container<std::vector>::type).name();
}

The code compiles fine with GCC 4.8.1 and Clang 3.4 but not with Visual Studio 2013. The error I get:

error C2976: 'std::vector' : too few template arguments
    c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see declaration of 'std::vector'
    c:\users\michał\documents\visual studio 2013\projects\transform\transform.cpp(14) : see reference to class template instantiation 'convert_container<std::vector>' being compiled

What does the standard say about this? Am I required to explicitly state all the parameters (including defaulted ones) when using the template template parameter C or is this just a bug in VC++?

Context: The issue araised from Constructor's answer to my previous question: http://stackoverflow.com/a/23874768/2617356

When searching the archives I've found this question: Default values in templates with template arguments ( C++ ) It's basically about the same problem, the question author states that default parameters for template template parameter "had to be" explicitly stated. However, the asker accepted solution that's not quite applicable in my case. The question was not about what is the standard-conforming behaviour, so I believe this is not a duplicate.

解决方案

Consider the similar

template <typename = void, int = 0> struct A { };
template <template <typename ...> class T> struct B : T<> { };
template class B<A>;

This is clearly covered by the standard (14.3.3p3 if you're interested, I won't quote it, as GCC and clang do both implement the rule already), where the use of A as a template argument for B is disallowed because of the non-type template parameter. That rule makes no sense if the instantiation of a template template parameter could make use of the template template argument's default template arguments, so the behaviour of MSVC and Intel is more consistent than that of GCC and clang.

Of course, the reasoning "if this were valid, the standard would have inconsistencies" doesn't actually mean it isn't valid, only that it shouldn't be valid. To actually check what the standard says:

14.1 Template parameters [temp.param]

10 The set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope in the same way default function arguments are (8.3.6).

8.3.6 Default arguments [dcl.fct.default]

4 Declarations in different scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa.

Although not specifically intended to address this use of default template arguments, I think it does manage to do so. Nikos Athanasiou has already included the part of the standard that says any default template arguments of C do get used:

14.1 Template parameters [temp.param]

14 A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.

Since C's default template arguments are used, std::vector's aren't, and MSVC and Intel seem to be correct here.

And to come up with an example that clearly shows that GCC and clang cannot be considered to conform here:

template <typename = char, typename = short>
struct A { };

template <template <typename = void, typename ...> class T>
struct B {
  using type = T<>;
};

Both GCC and clang treat B<A>::type as A<void, short>, taking one default template argument from T, and another from A, even though the standard disallows merging of default arguments (and hence default template arguments) in declarations in different scopes.


A workaround for you, to avoid the need to type out the allocator argument, could be to use a template alias:

template <template <class...> class C>
struct convert_container
{
  using type = C<double>; 
};

template <typename T>
using vector_default_alloc = std::vector<T>;

int main()
{
  std::cout << typeid(convert_container<vector_default_alloc>::type).name();
}

I cannot test on MSVC right now, but Intel accepts it, and I see no reason why this variant would be invalid.

这篇关于使用模板模板参数时是否需要显式列出默认参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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