【发布时间】:2017-08-04 16:08:55
【问题描述】:
我在一些实际的 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++ -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() {
^~~~~~~~~~~
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();
^~~~~~~~~~~
通过反复试验,我发现使用尾随返回类型可以获得与声明匹配的定义,从而产生also_working() 函数。在那里我意识到,由于尾随返回类型中范围的变化,我可以取消一些名称限定,从而产生更漂亮的working() 函数。
现在我想知道为什么not_working() 函数不起作用,即为什么它的定义与其声明不匹配(我可以对我找到的解决方案一无所知,但我可能会遇到更多此类问题,我不想浪费更多时间反复试验);该错误是在编译器中还是在我的代码中。我已通读 14.6 名称解析 [temp.res],但我不确定适用于这种情况的规则。
澄清问题:鉴于 C++11 标准中的规则:
-
not_working()定义是否应与声明匹配? - 确定 1.涉及哪些规则?
- 在确定 1. 时,来自 2. 的规则如何交互?
【问题讨论】:
-
奇怪但真实...使用 C++14 变量模板 compiles fine with g++, but still doesn't compile with clang++ 的相同代码。对我来说看起来像是一个编译器错误。
-
虽然没有解决这个特定问题,this core language issue 包含一个答案,暗示其目的是让离线定义与文本匹配的签名匹配声明。
-
auto可以帮助您处理无法编写的类型的地方之一。据我所知,gcc 和 clang 都对auto Foo<T>::working();感到满意,并且会在需要时推断返回类型。
标签: c++11 templates language-lawyer trailing-return-type