这部分功能模板是否专业化?

时间:2012-04-29 17:19:26

标签: c++ templates c++11 template-specialization initializer-list

我在回答this question

之后想出了这个

我有一个简单的函数模板(C ++ 11):

template<class elem_t, class list_t>
bool in_list(const elem_t& elem, const list_t& list) {
   for (const auto& i : list) {
      if (elem == i) {
         return true;
      }
   }
   return false;
}

但是GCC发出了警告,因为它似乎不喜欢将模板参数推断为std :: initializer_list。所以,不假思索地,我做了一个专业化:

template<class elem_t>
bool in_list(const elem_t& elem, std::initializer_list<elem_t> list) {
   for (const auto& i : list) {
      if (elem == i) {
         return true;
      }
   }
   return false;
}

这很有用。没有更多的警告。但当我再看一遍并考虑它时,我记得C ++不支持对函数模板进行部分模板特化。但这就是看起来的样子。我唯一的猜测是这是允许的,因为std :: initializer_list仍然依赖于模板参数,所以它本质上是一个不同的模板。但是我不确定它是不是应该是这样的(是不是有一些关于模板没有重载?)。

接受这个是标准行为吗?为什么?

作为奖励问题,为什么GCC不喜欢将模板参数推断为std :: initializer_list?期望我复制并粘贴代码并用std :: initializer_list替换参数似乎很愚蠢。

警告信息:

test.cpp: In function ‘int main()’:
test.cpp:33:43: warning: deducing ‘const list_t’ as ‘const std::initializer_list<int>’ [enabled by default]
test.cpp:6:6: warning:   in call to ‘bool in_list(const elem_t&, const list_t&) [with elem_t = int, list_t = std::initializer_list<int>]’ [enabled by default]
test.cpp:33:43: warning:   (you can disable this with -fno-deduce-init-list) [enabled by default]

in_list(3, {1, 2, 3, 4, 5});

调用时

编辑:显然,根据我的GCC版本(cite)的工作草案,将模板参数推断为initializer_list是一个扩展名。所以新问题:这仍然是最终c ++ 11标准的延伸吗?如果是这样,这意味着我需要为符合标准的代码添加第二个函数。感谢你的帮助!

EDIT2:GCC 4.7似乎删除了编译器方言标志,因此问题似乎已经解决,但我不知道 是如何解决的。

2 个答案:

答案 0 :(得分:4)

使用@Ben Voigt在其他答案的评论中所说的,我收集了一些相关的标准引用:

  

§14.5.6.2

     

功能模板可以与其他功能模板重载   并具有普通(非模板)功能。正常功能不是   与功能模板相关(即,从未被认为是a   专业化),即使它具有相同的名称和类型   可能生成的函数模板专业化

因此,排除函数模板特化作为你正在做的事情,因为即使两个函数模板重载可能潜在地生成相同的函数,它也不是特化。所以它正在超载。

  

此类专业化是不同的功能,不违反一个定义规则(3.2)。

所以它们是不同的功能,这就是它没有错误的原因。

  

§14.5.6.2.1

     

如果函数模板被重载,则使用函数模板   由于模板参数推导,特殊化*可能不明确   (14.8.2)可以将功能模板专业化与更多相关联   比一个函数模板声明。

这是我们已经看过的内容,in_list(a, b)其中b initializer_list似乎与两个功能模板匹配。

(*注意,“函数模板专门化”这里并不意味着专门化一个函数模板,它意味着一个已经用类型实例化的函数模板。因此template<typename T> f();f<int>()是一个功能模板专业化。)

所以我们使用所谓的重载函数模板的部分排序来解决这个问题:

  

重载函数模板声明的部分排序是   在以下上下文中用于选择函数的函数模板   模板专业化   是指:

     

- 在重载解析期间调用函数模板特化(13.3.3);

     

- 当采用功能模板专业化的地址时;

     

- 选择作为功能模板专门化的展示位置运算符时,选择匹配展示位置运算符new(3.7.4.2,5.3.4);

     

- 当友元函数声明(14.5.4),显式实例化(14.7.2)或显式特化(14.7.3)引用函数模板特化时。

好的,这就是部分订购的时候。这就是它的作用:

  

部分排序选择两个功能模板中的哪一个更多   通过依次转换每个模板来实现专业化(参见   下一段)并使用。执行模板参数推导   功能类型。扣除过程确定是否其中之一   模板比另一个更专业。如果是这样,就越多   专用模板是由部分排序选择的模板   过程

然后你进入了一个漫长而费力的过程,确定哪个模板更专业,如果你愿意,你可以阅读,但它真的很复杂,我可能根本不理解(加上,我不知道)有足够的时间来写它:))。

答案 1 :(得分:3)

这不是部分专业化。你正在做的是重载功能。