为啥我的模板不接受初始化列表

Posted

技术标签:

【中文标题】为啥我的模板不接受初始化列表【英文标题】:Why doesn't my template accept an initializer list为什么我的模板不接受初始化列表 【发布时间】:2011-06-13 01:23:59 【问题描述】:

我创建了一个模板如下

template<typename T>
void f(T const& t)  

我希望它可以被容器调用,也可以被初始化列表调用。我以为是initializer_list&lt;int&gt;,调用如下。

f(1, 2, 3);

但 GCC 的行为就好像它不符合标准

m.cpp: In function 'int main()':
m.cpp:6:25: warning: deducing 'const T' as 'const std::initializer_list<int>'
m.cpp:4:6: warning:   in call to 'void f(const T&) [with T = std::initializer_list<int>]'
m.cpp:6:25: warning:   (you can disable this with -fno-deduce-init-list)

谁能解释我如何在没有警告的情况下完成这项工作?谢谢!

【问题讨论】:

嗯,SO认为initializer_list标签是initializer-list的同义词似乎很不幸-.- C++0x会掉眼泪! AFAICS,它没有被定义为***.com/tags/initializer-list/synonyms 的同义词。是否有一些内置逻辑将x_y 替换为x-y 哦,没关系,我刚看到meta.stackexchange.com/questions/75798/… 我将只使用 std::initializer_list 【参考方案1】:

像 1,2,3 这样的“事物”不符合表达式的条件。它没有类型。因此,没有进行类型推导。但是 C++0x 为 'auto' 做了一个明确的例外,所以

auto x = 1,2,3;

确实有效,decltype(x) 将是initializer_list&lt;int&gt;。但这是一条仅适用于汽车的特殊规则。我猜他们想制作这样的循环

for (int x : 2,3,5,7,11) 
   ...

工作,因为这种循环利用了特殊规则。

至于解决问题,您可以添加一个initializer_list&lt;T&gt; 重载作为“包装器”:

template<class T>
inline void outer(initializer_list<T> il) 
   inner(il);

我没有对此进行测试,但我目前的理解是它应该可以工作。

【讨论】:

提到的特殊规则在 7.1.6.4 `auto' 说明符 [dcl.spec.auto] C++0x makes an explicit exception for 'auto' 是的,在你展示的类似赋值的语法中,还有auto somethinga, b, c 形式。后者一直是后部的不一致疼痛,现在只能用 C++17 修复,其中 auto somethingblah 没有 = 符号意味着 '创建 decltype(blah) 的对象,从 @ 初始化987654331@ - 不是 的当前含义'创建一个名为 somethinginitializer_list,其中一个元素与 blah' 类型相同。最后!但到此为止,这意味着对受影响的代码库进行大量更新。 :C【参考方案2】:

嗯,the documentation 这么说

之所以存在此选项,是因为此推论是对 C++0x 工作草案中当前规范的扩展,并且对潜在的重载解决问题存在一些担忧。

此信息可能只是过时了(根据来源,它最后一次更新是在 2008 年)。据我了解,该扣除已包含在 GCC 中,但期望该标准的后续草案会删除该规则,或至少对其进行限制。

【讨论】:

【参考方案3】:

谁能解释我如何在没有警告的情况下完成这项工作?

我不知道this 是否指的是您引用的确切代码,或者您是否只想知道如何使用初始化列表实例化函数模板而不触发警告,但如果是后者并且如果问题仅仅是推断正确的类型,你可以通过调用来避免它

f<initializer_list<int>>(1, 2, 3);

它并不漂亮,但它可以避免警告而无需摆弄编译器命令行参数。

我可能会在附近发表评论,说明由于某些 GCC 版本的弱点,您不依赖编译器推断正确的类型。

【讨论】:

以上是关于为啥我的模板不接受初始化列表的主要内容,如果未能解决你的问题,请参考以下文章

为啥初始化此类时不调用列表初始化?

为啥我不能在初始化列表中使用箭头运算符?

为啥 C++11 不支持指定初始化列表作为 C99? [关闭]

为啥 C++11 不支持指定初始化列表作为 C99? [关闭]

当初始化列表可用时,为啥现在使用可变参数?

为啥我更喜欢使用成员初始化列表?