在文章中多次阅读索赔 - 我想将此问题添加到Stackoverflow,并询问社区 - 以下代码是否可移植?
template<template<typename T, typename Alloc> class C>
void f() {
/* some code goes here ... */
}
int main() {
f<std::vector>();
}
提供std::vector
的实现是否真的允许具有超出两个众所周知的模板参数的额外默认模板参数?这会使上面的代码格式错误,因为它假设有两个模板参数。有关此类声明的示例,请参见最后一段in this article。
答案 0 :(得分:23)
我找到了以下issue report,其中包含
没有歧义;标准清晰如写。不允许库实现者将模板参数添加到标准库类。这不属于“似乎”规则,因此仅当标准为实现者提供明确许可时才允许这样做。这需要改变标准。
LWG决定不进行此更改,因为它会破坏涉及模板模板参数或标准库类模板特化的用户代码。
说明实施可能添加其他可选参数的书籍和人员似乎是错误的。
答案 1 :(得分:2)
令人难以置信的是,我最近阅读了“C ++模板:完整指南”,最后一本书在第111页上标记了以下内容:
模板模板参数必须是一个类模板,其参数与其替换的模板模板参数的参数完全匹配。将忽略模板模板参数的默认模板参数(但如果模板模板参数具有默认参数,则在模板实例化期间会考虑它们。)
因此,如果要相信本书,那么将非标准默认参数添加到std :: vector的示例将是合法的 - 因为模板模板参数的默认模板参数将被忽略。
作为一个真实世界的测试,我在g ++(成功)和Visual Studio 2008中编译了以下内容(在不匹配的参数上失败):
template<typename T1, typename T2, typename T3 = float>
class MyClass
{
public:
T1 v1;
T2 v2;
T3 v3;
};
template<template<typename T1, typename T2> class C>
void f()
{
C<int,double> *c = new C<int,double>();
}
int main ()
{
f<MyClass>();
return 0;
}
答案 2 :(得分:1)
检查17.4.4 [lib.conforming]的子小节。
17.4.4.3/3表示“实现不能将全局或非成员函数声明为采用其他默认参数”,但17.4.4.4/2明确允许用长文件替换所描述的成员函数签名,只要附加参数有默认值。
虽然没有模板部分,所以如果他们觉得需要提供17.4.4.3/3,我觉得额外的模板参数是允许的,禁止使用相反的措辞。
答案 3 :(得分:0)
我也看到了这个说法。但。
首先,我从未见过这样做的实现。我似乎记得Andrei Alexandrescu曾经考虑过使用类似于类固醇的分配器类型(类似my_fancy_thing<std::allocator,more_info_to_pass_to_the_container>
,而std::allocator
只会使用)。但即便如此,这仍然会使你的f()
工作,而这是一个最接近实施的东西,打破了我曾经听过的讨论的例子。
我认为这与声称0
指针不一定必须由所有位设置为零的值表示的声明属于同一类别 - 即使供应商确实拥有这种自由(我不知道,因为双方都有声称,他们也不会使用它,因为这基本上会破坏所有现有的代码。
所以我早就决定不担心了。