使用签名中的另一个成员模板函数定义外部成员模板函数定义

psy*_*ill 10 templates language-lawyer c++11 trailing-return-type

我在一些现实生活中的C++ 11代码中遇到了这个问题,但我把它归结为:

template<int i> struct Dummy {};

template<typename T>
struct Foo {
  template<int i> static constexpr int bar() { return i; }

  template<int i>
  static auto working() -> Dummy<bar<i>()>;

  template<int i>
  static auto also_working() -> Dummy<Foo<T>::template bar<i>()>;

  template<int i>
  static Dummy<Foo<T>::template bar<i>()> not_working();
};

template<typename T> template<int i>
auto Foo<T>::working() -> Dummy<bar<i>()> {
  return Dummy<bar<i>()>{};
}

template<typename T> template<int i>
auto Foo<T>::also_working() -> Dummy<Foo<T>::template bar<i>()> {
  return Dummy<bar<i>()>{};
}

template<typename T> template<int i>
Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
  return Dummy<bar<i>()>{};
}
Run Code Online (Sandbox Code Playgroud)

我试图创建一个模板类的模板成员函数的外联定义,其中函数的签名涉及调用另一个模板成员函数,并从函数开始not_working().问题是定义与声明不符.

克朗说:

clang++ -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -std=c++11   -c -o out_of_line.o out_of_line.cc
out_of_line.cc:28:42: error: out-of-line definition of 'not_working' does not match any declaration in 'Foo<T>'
Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
                                         ^~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

GCC说:

g++ -Wall -Wextra -pedantic -std=c++11   -c -o out_of_line.o out_of_line.cc
out_of_line.cc:28:34: error: prototype for ‘Dummy<bar<i>()> Foo<T>::not_working()’ does not match any in class ‘Foo<T>’
 Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
                                  ^~~~~~
out_of_line.cc:14:43: error: candidate is: template<class T> template<int i> static Dummy<Foo<T>::bar<i>()> Foo<T>::not_working()
   static Dummy<Foo<T>::template bar<i>()> not_working();
                                       ^~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

通过反复试验,我发现使用尾随返回类型我可以得到与声明匹配的定义,从而产生also_working()函数.在那里我意识到由于尾随返回类型中范围的改变,我可以取消一些名称限定,产生更漂亮的working()功能.

现在我想知道为什么not_working()函数不起作用,即为什么它的定义与它的声明不符(我可能只是对我发现的解决方案无知,但我可能会遇到更多这类问题而我不会想浪费更多时间使用反复试验); 错误是在编译器内还是在我的代码中.我已经阅读了14.6名称解析[temp.res],但我不确定哪种规则适用于这种情况.

澄清问题:鉴于C++ 11标准中的规则:

  1. not_working()定义是否应与声明相符?
  2. 确定1中涉及哪些规则?
  3. 2.确定1时,规则如何相互作用?

TBB*_*Ble 0

看起来它正在尝试实施CWG2,但可能会以令人惊讶的顺序进行操作。查看gcc的错误:

prog.cc:28:34: error: prototype for 'Dummy<bar<i>()> Foo<T>::not_working()' does not match any in class 'Foo<T>'
 Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
                                  ^~~~~~
prog.cc:14:43: error: candidate is: template<class T> template<int i> static Dummy<Foo<T>::bar<i>()> Foo<T>::not_working()
   static Dummy<Foo<T>::template bar<i>()> not_working();
                                           ^~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

定义带有返回类型Dummy<bar<i>()>,但候选声明具有返回类型Dummy<Foo<T>::bar<i>()>。具体来说,已经失去了Foo<T>::资格。bar<i>

更改 的定义以also_working具有返回类型Dummy<Foo<T>::template bar<2>()>,我们得到有用的并行错误:

prog.cc:23:6: error: prototype for 'Dummy<Foo<T>::bar<2>()> Foo<T>::also_working()' does not match any in class 'Foo<T>'
 auto Foo<T>::also_working() -> Dummy<Foo<T>::template bar<2>()> {
      ^~~~~~
prog.cc:11:15: error: candidate is: template<class T> template<int i> static Dummy<Foo<T>::bar<i>()> Foo<T>::also_working()
   static auto also_working() -> Dummy<Foo<T>::template bar<i>()>;
               ^~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

这里的定义带有返回类型Dummy<Foo<T>::bar<2>()>(如所写),并且候选声明具有返回类型Dummy<Foo<T>::bar<i>()>

显然,甚至在 的上下文中也Foo<T>::bar<i>不同,因为删除返回类型的声明或定义会使其停止工作。(把两者都拿出来就可以回来。)bar<i> Foo<T>Foo<T>::templatealso_workingworking

我尝试将 的声明更改not_working为:

  template<int i>
  static Dummy<bar<i>()> not_working();
Run Code Online (Sandbox Code Playgroud)

现在海湾合作委员会抱怨:

prog.cc:28:34: error: prototype for 'Dummy<bar<i>()> Foo<T>::not_working()' does not match any in class 'Foo<T>'
 Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
                                  ^~~~~~
prog.cc:14:26: error: candidate is: template<class T> template<int i> static Dummy<bar<i>()> Foo<T>::not_working()
   static Dummy<bar<i>()> not_working();
                          ^~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

Dummy<bar<i>()> Foo<T>::not_working()这显然是荒谬的,因为一旦编译器完成了它,我们就有了逐个字符可比较的声明和定义。