提问人:psyill 提问时间:3/14/2017 最后编辑:psyill 更新时间:5/16/2017 访问量:410
在签名中使用另一个成员模板函数的行外成员模板函数定义
Out-of-line member template function definition using another member template function in the signature
问:
我在一些现实生活中的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>()>{};
}
我试图创建一个模板类的模板成员函数的行外定义,其中函数的签名涉及调用另一个模板成员函数,并从类似函数的东西开始。问题在于定义与声明不符。not_working()
Clang 说:
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() {
^~~~~~~~~~~
海湾合作委员会 说:
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();
^~~~~~~~~~~
通过反复试验,我发现使用尾随返回类型,我可以获得与声明匹配的定义,从而产生函数。到达那里后,我意识到由于尾随返回类型的范围发生了变化,我可以取消一些名称限定,从而产生更漂亮的函数。also_working()
working()
现在我想知道为什么该函数不起作用,即为什么它的定义与其声明不匹配(我可以对我找到的解决方案一无所知,但我可能会遇到更多此类问题,我不想浪费更多时间使用反复试验);错误是在编译器中还是在我的代码中。我已经通读了 14.6 名称解析 [temp.res],但我不确定适用于这种情况的规则。not_working()
澄清问题:给定 C++11 标准中的规则:
- 定义是否应与声明相符?
not_working()
- 确定 1.?
- 规则如何从 2.确定 1.?
答:
看起来它正在尝试实现 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();
^~~~~~~~~~~
定义与返回类型一起看到,但候选声明具有返回类型。具体来说,资格已经丧失。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>()>;
^~~~~~~~~~~~
这里的定义是带有返回类型(如所写)的,候选声明具有返回类型。Dummy<Foo<T>::bar<2>()>
Dummy<Foo<T>::bar<i>()>
显然,它甚至与 Foo<T>
的上下文不同,因为从返回类型的声明或定义中删除会使其停止工作。(把两者都拿出来可以让你回来。Foo<T>::bar<i>
bar<i>
Foo<T>::template
also_working
working
我尝试将声明更改为:not_working
template<int i>
static Dummy<bar<i>()> not_working();
现在 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:26: error: candidate is: template<class T> template<int i> static Dummy<bar<i>()> Foo<T>::not_working()
static Dummy<bar<i>()> not_working();
^~~~~~~~~~~
这显然是荒谬的,因为一旦编译器完成它,我们就会有字符对字符的可比声明和定义。Dummy<bar<i>()> Foo<T>::not_working()
评论
auto
auto Foo<T>::working();