简体   繁体   English

模板专门化和显式指定返回类型与自动

[英]Template specialization and explicit specification of return type vs. auto

Consider the code: 考虑一下代码:

class Test {
public:
    template<int N> auto foo() {}
    template<> auto foo<0>() { return 7;  }

    template<int N> void bar() {}
    template<> int bar<0>() { return 7;  }
};

I have tested the code with different compilers (through Compiler Explorer ). 我已经使用不同的编译器(通过Compiler Explorer )测试了代码。

In case of Clang 7.0.0 foo compiles, while bar is giving an error: 如果使用Clang 7.0.0 ,则foo编译,而bar给出错误:

:8:20: error: no function template matches function template specialization 'bar' :8:20:错误:没有功能模板与功能模板专业化“酒吧”匹配

 template<> int bar<0>() { return 7; } ^ 

:7:26: note: candidate template ignored: could not match 'void ()' against 'int ()' :7:26:注意:候选模板被忽略:无法将'void()'与'int()'相匹配

 template<int N> void bar() {}; ^ 

Visual C++ agrees (MSVC 19 2017 RTW): Visual C ++同意(MSVC 19 2017 RTW):

(8): error C2912: explicit specialization 'int Test::bar(void)' is not a specialization of a function template (8):错误C2912:显式专门化'int Test :: bar(void)'不是功能模板的专门化

gcc 8.2 does not compile any of the code (though the reason is probably a bug in C++17 support : gcc 8.2不会编译任何代码(尽管原因可能是C ++ 17支持中错误

:5:14: error: explicit specialization in non-namespace scope 'class Test' :5:14:错误:非命名空间范围“类测试”中的显式专业化

  template<> auto foo<0>() { return 7; }; ^ 

:5:28: error: template-id 'foo<0>' in declaration of primary template :5:28:错误:主模板的声明中的template-id'foo <0>'

  template<> auto foo<0>() { return 7; }; ^ 

:7:26: error: too many template-parameter-lists :7:26:错误:模板参数列表过多

  template<int N> void bar() {}; ^~~ 

:8:14: error: explicit specialization in non-namespace scope 'class Test' :8:14:错误:非命名空间范围“类测试”中的显式专业化

  template<> int bar<0>() { return 7; } ^ 

:8:20: error: expected ';' :8:20:错误:预期为';' at end of member declaration 在成员声明结束时

  template<> int bar<0>() { return 7; } ^~~ ; 

:8:23: error: expected unqualified-id before '<' token :8:23:错误:“ <”令牌之前的预期unqualified-id

  template<> int bar<0>() { return 7; } ^ 

What is the correct interpretation here? 这里的正确解释是什么? Can I have a different return type for different method specializations (and why only with auto , but not while specifying them explicitly)? 我可以针对不同的方法专长使用不同的返回类型吗(为什么只使用auto ,而没有在明确指定它们时指定)? With my limited understanding of auto and templates I would go with saying "no". 由于对auto和template的了解有限,我会说“ no”。 I don't understand why would using auto instead of explicitly naming the return type allow to have different return type for different specializations. 我不明白为什么要使用auto而不是显式命名返回类型来允许针对不同的专业使用不同的返回类型。

However, those codes are simplified versions of the code that I have found elsewhere , so maybe my interpretation is incorrect - and in that case I would be grateful for the explanation why different return type is allowed when auto is used for specialization, while explicitly naming the type seems to be forbidden . 但是,这些代码是我在其他地方找到的代码的简化版本,所以也许我的解释不正确-在那种情况下,我将不胜感激地解释为什么将auto用于专业化时为什么允许使用不同的返回类型,同时明确命名该类型似乎是被禁止的

There are several different problems with the example code. 示例代码有几个不同的问题。

1) GCC fails to implement CWG 727 (required in C++17): https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 which causes error: explicit specialization in non-namespace scope 'class Test' 1)GCC无法实现CWG 727(在C ++ 17中是必需的): https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282会导致error: explicit specialization in non-namespace scope 'class Test'

2) If we ignore that, the example code can be simplified to just 2)如果我们忽略这一点,示例代码可以简化为

template<int N> auto foo() {}
template<> auto foo<0>() { return 7; }

template<int N> void bar() {}
template<> int bar<0>() { return 7; }

which still exhibits the same errors. 仍然显示相同的错误。 Now all compilers agree on the output. 现在,所有编译器都同意输出。 They compile foo s and error out on the bar specialization. 他们编译foo s并在专业bar上出错。

why different return type is allowed when auto is used for specialization 为什么使用auto进行专业化时为何允许不同的返回类型

It is allowed by a standard to specialize functions with auto return type if the specializations also have auto placeholder 如果专业化也具有auto占位符,则标准允许使用auto返回类型的专业化功能

Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type 具有使用占位符类型的已声明返回类型的函数或函数模板的重新声明或特化也应使用该占位符,而不是推导类型

http://eel.is/c++draft/dcl.spec.auto#11 http://eel.is/c++draft/dcl.spec.auto#11

So by virtue of this specialization conforming to the standard (being similar to one of the given examples) and not being explicitly forbidden anywhere it's allowed. 因此,凭借符合标准的专业化(类似于给定的示例之一),并且在任何允许的地方都没有明确禁止。

As for the error with bar , the standard says that return type is a part of function template signature: 至于bar的错误,标准说返回类型是函数模板签名的一部分:

⟨function template⟩ name, parameter type list ([dcl.fct]), enclosing namespace (if any), return type , template-head, and trailing requires-clause ([dcl.decl]) (if any) “功能模板”的名称,参数类型列表([dcl.fct]),封闭的名称空间(如果有的话), 返回类型 ,模板头和尾随的要求子句([dcl.decl])(如果有的话)

http://eel.is/c++draft/defns.signature.templ http://eel.is/c++draft/defns.signature.templ

As such, in compiler's eyes template<> int bar<0>() { return 7; } 因此,在编译器看来, template<> int bar<0>() { return 7; } template<> int bar<0>() { return 7; } is a specialization of template<... N> int bar(); template<> int bar<0>() { return 7; }template<... N> int bar();的特殊化template<... N> int bar(); template (notice the return type). 模板(注意返回类型)。 But it wasn't declared previously (specialization can't precede declaration) so compilation fails! 但是以前没有声明过(专业化不能在声明之前),所以编译失败! If you add template<int N> int bar(); 如果添加template<int N> int bar(); then it'll compile (but complain about call ambiguity if you try to call bar ). 然后它将进行编译(但是如果您尝试调用bar则会抱怨调用不明确)。

Basically, you can't change the function signature in a specialization, you can only specialize (duh) template parameters (which should also be exactly the same as in declaration, since it's also part of the signature). 基本上,您不能以特殊化方式更改函数签名,只能对(duh)模板参数进行特殊化处理(模板参数也应与声明中的参数完全相同,因为它也是签名的一部分)。

Can I have a template specialization with explicitly declared return type different from the base template at all 我是否可以拥有一个模板专门化,其显式声明的返回类型与基本模板完全不同

As explained - you can't change the function template signature which means you can't change the return type. 如前所述-您无法更改函数模板签名,这意味着您无法更改返回类型。 BUT, you can specialize the return type if it depends on a template parameter! 但是,如果返回类型取决于模板参数,则可以对其进行专门化处理!

Consider 考虑

template<int N, typename R = void> R bar() {}
template<> int bar<0>() { return 7; }
// bar<0, int> is deduced, see: http://eel.is/c++draft/temp.expl.spec#10

This is allowed but it has a disadvantage of having to write bar<0, int> when you want to make a call to a specialization: https://godbolt.org/z/4lrL62 这是允许的,但是它有一个缺点,当您要调用特殊化时必须写bar<0, int>https : //godbolt.org/z/4lrL62

This can be worked around by making the type conditional in the original declaration: https://godbolt.org/z/i2aQ5Z 可以通过在原始声明中将条件类型设置为条件来解决此问题: https : //godbolt.org/z/i2aQ5Z

But it'll quickly become cumbersome to maintain once the number of specializations grows. 但是一旦专业化的数量增加,要维护它很快就会变得很麻烦。

Another, perhaps a bit more maintainable option, would be to return something like ret_type<N>::type and specialize that along with bar . 另一个也许更可维护的选项是返回类似ret_type<N>::type东西,并将其与bar一起专门化。 But it's still won't be as clean as with just using auto . 但是它仍然不会像使用auto那样干净。

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

相关问题 如何使用具有显式特化的另一个模板参数推断模板返回类型? - How to deduce template return type with another template parameter with explicit specialization? 具有不同返回类型的显式专业化模板类成员函数 - explicit specialization template class member function with different return type 是否有规定在 function 模板显式专业化中指定对“返回类型”的限制? - Is there provision specifying the restriction on "return type" in a function template explicit specialization? 什么时候返回类型不完全是返回类型? (模板专业化,“自动”) - When is a return type not exactly a return type? (template specialization, “auto”) 具有明确类型说明的功能模板 - Function template with explicit specification of type C ++函数模板特化声明和模板参数; none vs. <> vs. <type> - C++ function template specialization declarations and template arguments; none vs. <> vs. <type> 函数模板重载vs显式特化 - Function template overloading vs Explicit specialization 模板专业化与默认值 - Template specialization vs. default values 模板专业化与编译器优化 - Template specialization vs. Compiler optimization 模板函数专业化与重载 - Template function specialization vs. overloading
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM