简体   繁体   English

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

[英]Is this partial function template specialization?

I came up with this after answering this question 回答完这个问题后,我想到了这个

I had a simple function template (C++11): 我有一个简单的函数模板(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;
}

But GCC emitted warnings because it doesn't seem to like deducing a template parameter as a std::initializer_list. 但是GCC发出了警告,因为它似乎不喜欢将模板参数推断为std :: initializer_list。 So, without thinking, I made a specialization: 所以,不假思索地,我做了一个专业化:

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;
}

This worked. 这很有效。 No more warnings. 没有更多的警告。 But when I looked again and thought about it, I remembered that C++ does not support partial template specialization on function templates. 但当我再看一遍并考虑它时,我记得C ++不支持对函数模板进行部分模板特化。 But that is what this appears to be. 但这就是看起来的样子。 My only guess is that this is allowed because std::initializer_list is still dependent upon the template parameter, so it is, in essence, a different template. 我唯一的猜测是这是允许的,因为std :: initializer_list仍然依赖于模板参数,所以它本质上是一个不同的模板。 But I'm not sure if this is how it is supposed to be (isn't there a gotw about templates not overloading?). 但我不确定这是不是应该是这样(是不是有一些模板没有重载?)。

Is it standard behavior to accept this? 接受这个是标准行为吗? And why? 为什么?

And as a bonus question, why does GCC not like deducing a template parameter as a std::initializer_list? 作为一个额外的问题,为什么GCC不喜欢将模板参数推断为std :: initializer_list? It seems quite silly to expect me to copy and paste the code and just replace the parameter with a std::initializer_list. 期望我复制并粘贴代码并用std :: initializer_list替换参数似乎很愚蠢。

The warning message: 警告信息:

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]

When called by in_list(3, {1, 2, 3, 4, 5}); 当被in_list(3, {1, 2, 3, 4, 5});

EDIT: Apparently deducing a template parameter as an initializer_list is an extension according to the working draft for my version of GCC ( cite ). 编辑:显然推断模板参数作为initializer_list是根据我的GCC版本( 引用 )的工作草案的扩展。 So new question: Is this still an extension as of the final c++11 standard? 所以新问题:这仍然是最终c ++ 11标准的延伸吗? If so, this would mean that it would be necessary for me to add the second function for standards-compliant code. 如果是这样,这意味着我需要为符合标准的代码添加第二个函数。 Thanks for all your help! 感谢你的帮助!

EDIT2: The compiler dialect flag appears to be removed for GCC 4.7, so it seems like the issue was resolved, but I don't know how it was resolved. EDIT2:GCC 4.7似乎删除了编译器方言标志,因此问题似乎已经解决,但我不知道它是如何解决的。

Using what @Ben Voigt said in the comments on the other answer, I have gathered some relevant standard quotes: 使用@Ben Voigt在其他答案的评论中所说的,我收集了一些相关的标准引用:

§14.5.6.2 §14.5.6.2

A function template can be overloaded with other function templates and with normal (non-template) functions. 功能模板可以使用其他功能模板和普通(非模板)功能重载。 A normal function is not related to a function template (ie, it is never considered to be a specialization ), even if it has the same name and type as a potentially generated function template specialization . 普通函数与函数模板无关(即,它永远不会被认为是特化 ), 即使它与可能生成的函数模板特化具有相同的名称和类型

So that rules out function template specialisation as what you're doing, because even if two function template overloads could potentially generate the same function, it's not specialisation. 因此,排除函数模板特化作为你正在做的事情,因为即使两个函数模板重载可能潜在地生成相同的函数,它也不是特化。 So it's overloading. 所以它超载了。

Such specializations are distinct functions and do not violate the one definition rule (3.2). 这种专业化是不同的功能,不违反一个定义规则(3.2)。

So they're distinct functions and that's why it's not erroring. 所以它们是不同的功能,这就是为什么它没有错误。

§14.5.6.2.1 §14.5.6.2.1

If a function template is overloaded, the use of a function template specialization* might be ambiguous because template argument deduction (14.8.2) may associate the function template specialization with more than one function template declaration. 如果函数模板被重载,则函数模板特化*的使用可能不明确,因为模板参数推导(14.8.2)可能将函数模板特化与多个函数模板声明相关联。

This is priming is for what we both already saw, which is that in_list(a, b) where b is an initializer_list appears to match both function templates. 这是我们已经看到的启动,即in_list(a, b) ,其中binitializer_list似乎与两个函数模板匹配。

(*Note that "function template specialization" here doesn't mean specialising a function template, it means a function template that has been instantiated with a type. So with template<typename T> f(); , f<int>() is a function template specialisation.) (*请注意,“函数模板特化”这里并不意味着专门化一个函数模板,它意味着一个已经用类型实例化的函数模板。所以使用template<typename T> f(); f<int>()是一个功能模板专业化。)

So we use what is called partial ordering of overloaded function templates to resolve this: 所以我们使用所谓的重载函数模板的部分排序来解决这个问题:

Partial ordering of overloaded function template declarations is used in the following contexts to select the function template to which a function template specialization refers: 在以下上下文中使用重载函数模板声明的部分排序来选择函数模板特化引用的函数模板:

— during overload resolution for a call to a function template specialization (13.3.3); - 在重载解析期间调用函数模板专门化(13.3.3);

— when the address of a function template specialization is taken; - 当采用功能模板专业化的地址时;

— when a placement operator delete that is a function template specialization is selected to match a placement operator new (3.7.4.2, 5.3.4); - 当选择放置运算符delete作为函数模板时,选择特殊化以匹配放置运算符new(3.7.4.2,5.3.4);

— when a friend function declaration (14.5.4), an explicit instantiation (14.7.2) or an explicit specialization (14.7.3) refers to a function template specialization. - 当朋友函数声明(14.5.4),显式实例化(14.7.2)或显式特化(14.7.3)引用函数模板特化时。

Ok, so that's when partial ordering is for. 好的,这就是部分订购的时候。 This is what it does: 这就是它的作用:

Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. 部分排序通过依次转换每个模板(参见下一段)并使用函数类型执行模板参数推导来选择两个函数模板中哪一个比另一个更专业。 The deduction process determines whether one of the templates is more specialized than the other. 演绎过程确定其中一个模板是否比另一个模板更专业。 If so, the more specialized template is the one chosen by the partial ordering process. 如果是这样,则更专业的模板是由部分排序过程选择的模板。

And then you get into the long and laborious process of determining which template is more specialised, which you can read about if you want, but it's really complicated and I probably don't understand it all (and plus, I don't have enough time to write about it :)). 然后你进入了一个漫长而费力的过程,确定哪个模板更专业,如果你愿意,你可以阅读,但它真的很复杂,我可能根本不理解(加上,我没有足够的写下来的时间:))。

That's not partial specilization. 这不是局部的说明。 What you are doing is overloading function. 你正在做的是重载功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM