我想问一下下面的代码示例是否应该编译:
#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();
}
Run Code Online (Sandbox Code Playgroud)
代码可以使用GCC 4.8.1和Clang 3.4编译,但不适用于Visual Studio 2013.我得到的错误:
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
Run Code Online (Sandbox Code Playgroud)
标准对此有何看法?我是否需要在使用模板模板参数时明确声明所有参数(包括默认参数),C或者这只是VC++中的错误?
上下文:从构造函数回答上一个问题的问题:https ://stackoverflow.com/a/23874768/2617356
在搜索档案时,我发现了这个问题:带有模板参数的模板中的默认值(C++) 它基本上是关于同一个问题,问题作者声明模板模板参数的默认参数"必须"明确说明.但是,提问者接受的解决方案在我的案例中并不适用.问题不在于什么是符合标准的行为,所以我认为这不是重复的.
小智 3
考虑类似的
template <typename = void, int = 0> struct A { };
template <template <typename ...> class T> struct B : T<> { };
template class B<A>;
Run Code Online (Sandbox Code Playgroud)
标准明确涵盖了这一点(如果您感兴趣,14.3.3p3,我不会引用它,因为 GCC 和 clang 都已经实现了该规则),其中不允许使用 作为A模板参数,B因为非类型模板参数。如果模板模板参数的实例化可以使用模板模板参数的默认模板参数,则该规则没有任何意义,因此 MSVC 和 Intel 的行为比 GCC 和 clang 的行为更加一致。
当然,“如果这是有效的,标准就会不一致”的推理实际上并不意味着它无效,只是它不应该有效。要实际检查标准的内容:
14.1 模板参数[temp.param]
10 可与模板声明或定义一起使用的默认模板参数集是通过合并定义中的默认参数(如果在范围内)和范围内的所有声明以默认函数参数相同的方式获得的(8.3.6) 。
8.3.6 默认参数 [dcl.fct.default]
4 不同作用域中的声明具有完全不同的默认参数集。也就是说,内部作用域中的声明不会从外部作用域中的声明获取默认参数,反之亦然。
虽然不是专门为了解决默认模板参数的使用问题,但我认为它确实做到了这一点。Nikos Athanasiou 已经包含了标准的一部分,该部分规定C使用 do 的任何默认模板参数:
14.1 模板参数[temp.param]
14模板 template-parameter的 template -parameter允许有默认template-argument。当指定此类默认参数时,它们将应用于模板template-parameter范围内的模板template-parameter。
由于C使用了 的默认模板参数,因此std::vector没有使用 ,并且 MSVC 和 Intel 在这里似乎是正确的。
并举出一个例子来清楚地表明 GCC 和 clang 不能被认为在这里符合:
template <typename = char, typename = short>
struct A { };
template <template <typename = void, typename ...> class T>
struct B {
using type = T<>;
};
Run Code Online (Sandbox Code Playgroud)
GCC 和 clang 都将B<A>::typeas视为A<void, short>,从 中获取一个默认模板参数T,从 中获取另一个A默认模板参数,尽管标准不允许在不同作用域的声明中合并默认参数(因此默认模板参数)。
为了避免需要键入分配器参数,您可以使用一个解决方法:使用模板别名:
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();
}
Run Code Online (Sandbox Code Playgroud)
我现在无法在 MSVC 上进行测试,但英特尔接受它,而且我认为这个变体没有理由无效。
| 归档时间: |
|
| 查看次数: |
1344 次 |
| 最近记录: |