当前位置: 首页 > 知识库问答 >
问题:

返回类型与自动的模板专门化和显式规范

昝宜
2023-03-14

考虑代码:

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

我用不同的编译器(通过编译器资源管理器)测试了代码。

如果Clang 7.0.0foo编译,而bar给出错误:

:8:20:错误:没有与函数模板专用化“栏”匹配的函数模板

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

               ^

:7:26:注意:已忽略候选模板:无法将'void()'与'int()'匹配

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

                     ^

Visual C同意(MSVC 19 2017 RTW):

(8) :错误C2912:显式专门化“int Test::bar(void)”不是函数模板的专门化

gcc 8.2不编译任何代码(尽管原因可能是C 17支持中的错误:

: 5:14:错误:非命名空间范围'class Test'中的显式特化

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

          ^

:5:28:错误:模板id'foo

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

                        ^

: 7:26:错误:模板参数列表太多

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

                      ^~~

:8:14:错误:非命名空间范围“类测试”中的显式专门化

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

          ^

:8:20:错误:应为“;”在成员声明末尾

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

                ^~~

                   ;

:8:23:错误:在'

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

                   ^

这里的正确解释是什么?我可以为不同的方法特化提供不同的返回类型吗(为什么只能使用auto,但不能显式指定它们)?由于我对auto和模板的理解有限,我会说“不”。我不明白为什么使用auto而不是显式命名返回类型允许为不同的特化提供不同的返回类型。

然而,这些代码是我在其他地方找到的代码的简化版本,因此可能我的解释是错误的——在这种情况下,我将感谢您解释为什么在使用auto进行专门化时允许使用不同的返回类型,而显式命名类型似乎是被禁止的。

共有1个答案

柴星津
2023-03-14

示例代码有几个不同的问题。

1) GCC未能实施CWG 727(C 17中要求):https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282这会导致错误:在非命名空间范围的“类测试”中显式专门化

2)如果我们忽略它,示例代码可以简化为

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

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

这仍然显示出同样的错误。现在所有的编译器都同意输出。他们编译foos,并在条上出错。

为什么在使用auto进行专业化时允许使用不同的返回类型

如果专门化还具有auto占位符,则标准允许专门化带有auto返回类型的函数

对使用占位符类型的已声明返回类型的函数或函数模板的重新声明或专门化也应使用该占位符,而不是推断类型

http://eel.is/c草案/dcl.spec.auto#11

因此,由于这种专业化符合标准(类似于给定的一个示例),并且在任何允许的地方都没有被明确禁止。

至于bar的错误,标准说返回类型是函数模板签名的一部分:

函数模板name、参数类型列表([dcl.fct])、封闭命名空间(如果有)、返回类型、模板头和尾随的要求子句([dcl.decl])(如果有)

http://eel.is/c草稿/定义。签名圣堂

同样地,在编译器眼中模板

基本上,您不能在专门化中更改函数签名,只能专门化(duh)模板参数(这也应该与声明中完全相同,因为它也是签名的一部分)。

我可以有一个明确声明的返回类型与基本模板完全不同的模板特化吗

如前所述,您不能更改函数模板签名,这意味着您不能更改返回类型。但是,如果返回类型依赖于模板参数,则可以对其进行专门化!

考虑

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

这是允许的,但它的缺点是必须编写bar

这可以通过在原始声明中设置类型条件来解决:https://godbolt.org/z/i2aQ5Z

但一旦专业化的数量增加,维护起来就会变得很麻烦。

另一个可能更易于维护的选项是返回类似ret_type的内容

 类似资料:
  • 我有一些代码使用两种不同类型的颜色,每个通道8位和每个通道16位,每个都由一个结构表示。为了有效地重用我的代码,我有一个模板函数可以对它们进行一些渲染。因此,我希望有一个模板函数来获取我的颜色通道的最大值。 我最初的尝试是这样的。我只展示了8 bpc的专业化 这不会在Visual studio 2012中编译。我明白了 1个 对我来说,我觉得这应该行得通,但我一直找不到任何例子。在Speciali

  • 我想编写一个函数模板,它返回各种类型的随机变量(bool、char、short、int、float、double,以及这些变量的无符号版本)。 我看不出如何使用最新的C 11标准库来实现这一点,因为我需要使用统一的int分布或统一的real分布。我想我可以专门化模板: 在Visual Studio 2012 Update 3下,这给出了: 错误C2668:“‘匿名命名空间’::randomPrim

  • 在本文中,他们说(c)是(b)的显式专门化。我的疑问是,为什么我们不能说它是(a)的显式专门化?因为我们可以为任何特定类型专门化模板。所以,当专门化int*时,为什么他们说(c)显式专门化(b)。 任何评论都将有助于理解事情。

  • 在C 11中,如何专门化一个函数模板,该模板使用decltype声明为“复杂”的尾部返回类型?以下内容适用于GCC,但在VC2013中产生了“错误C2912:显式专业化‘int f(void)’i不是功能模板的专业化”: 我说“复杂”是因为缺乏一个技术上精确的词,因为我不确定是什么造成了差异。例如,以下decltype使用不依赖于任何函数结果类型的内置操作,可以与模板专业化配合使用: 自动f()-

  • 我想用两种模板类型编写一个模板化函数:一种是bool,另一种是typename,我想专门研究typename。 这就是我想要的,但只针对T的几种类型: 没有bool在那里,我可以做这样的事情: 我搞不懂这句话的语法,而专门化方面的微软文档只涉及单一类型的情况。

  • 我有一个通用算法,需要访问其模板类型的特征。有一个特征类可以专门用于提供这些特征。 在我的类中使用此算法时,我想将其与类中定义的私有类型一起使用。 然而,专门化只能发生在或全局范围内,而我的类是不可访问的。 是否有可能以某种方式专门化具有私有类型的模板,至少在可访问此类型的范围内? 也许可以将这个专门化声明为一个类?