为什么偏特化不需要前向声明?
Why doesn't partial specialization need forward declaration?
今天写了下面的代码,出错了:
template<int V>
typename std::enable_if<(V > 0)>::type
Test() {
Test<V - 1>();
}
template<int V>
typename std::enable_if<(V == 0)>::type
Test() {
std::cout << "0" << std::endl;
}
int main() {
Test<1>();
}
编译器错误我的那个no matching function for call to ‘Test<(1 - 1)>()’
,我检查发现我应该把std::enable_if<(V == 0)>::type
版本放在第一位,或者,我使用这样的前向声明:
// forward declaration
template<int V>
typename std::enable_if<(V == 0)>::type
Test();
template<int V>
typename std::enable_if<(V > 0)>::type
Test() {
Test<V - 1>();
}
template<int V>
typename std::enable_if<(V == 0)>::type
Test() {
std::cout << "0" << std::endl;
}
int main() {
Test<1>();
}
我注意到,当我使用部分特化编写代码时,我以前从未遇到过这个问题,例如:
template <int V, typename = void>
struct Foo {
static void Test() {
std::cout << V << std::endl;
Foo<V - 1>::Test();
}
};
template <int V>
struct Foo <V, typename std::enable_if<V == 0>::type> {
static void Test() {
std::cout << "0" << std::endl;
}
};
int main() {
Foo<1>::Test();
}
这段代码可以找到并且我没有使用前向声明,所以这是我的问题:
为什么函数版本不能“看到”其自身之后的函数声明,而结构版本却知道? SFINAE在函数版的编译中出现了吗?
P.S。这是使用 clang 的错误消息,看起来更具体:
/home/liu/source/untitled4/main.cpp:7:3: error: call to function 'Test' that is neither visible in the template definition nor found by argument-dependent lookup
Test<V - 1>();
这是我在使用 GCC 的问题中提到的错误消息:
/home/liu/source/untitled4/main.cpp:7:14: error: no matching function for call to ‘Test<(1 - 1)>()’
Test<V - 1>();
而且我手上暂时没有Windows环境,如果MSVC报错我会稍后贴上。
虽然评论已经解决了问题——每个独立函数模板必须在使用前声明——关于差异的问题 可以简单地通过引用 [temp.class.spec.general]/7:
来回答
Partial specialization declarations themselves are not found by name lookup. Rather, when the primary template name is used, any previously-declared partial specializations of the primary template are also considered. […]
因此,从 实例化点 可用的特化是可用的,因此可以在任何实例化之前自由地进行相互引用。 (这类似于查找 dependent 函数名称的规则。)
今天写了下面的代码,出错了:
template<int V>
typename std::enable_if<(V > 0)>::type
Test() {
Test<V - 1>();
}
template<int V>
typename std::enable_if<(V == 0)>::type
Test() {
std::cout << "0" << std::endl;
}
int main() {
Test<1>();
}
编译器错误我的那个no matching function for call to ‘Test<(1 - 1)>()’
,我检查发现我应该把std::enable_if<(V == 0)>::type
版本放在第一位,或者,我使用这样的前向声明:
// forward declaration
template<int V>
typename std::enable_if<(V == 0)>::type
Test();
template<int V>
typename std::enable_if<(V > 0)>::type
Test() {
Test<V - 1>();
}
template<int V>
typename std::enable_if<(V == 0)>::type
Test() {
std::cout << "0" << std::endl;
}
int main() {
Test<1>();
}
我注意到,当我使用部分特化编写代码时,我以前从未遇到过这个问题,例如:
template <int V, typename = void>
struct Foo {
static void Test() {
std::cout << V << std::endl;
Foo<V - 1>::Test();
}
};
template <int V>
struct Foo <V, typename std::enable_if<V == 0>::type> {
static void Test() {
std::cout << "0" << std::endl;
}
};
int main() {
Foo<1>::Test();
}
这段代码可以找到并且我没有使用前向声明,所以这是我的问题:
为什么函数版本不能“看到”其自身之后的函数声明,而结构版本却知道? SFINAE在函数版的编译中出现了吗?
P.S。这是使用 clang 的错误消息,看起来更具体:
/home/liu/source/untitled4/main.cpp:7:3: error: call to function 'Test' that is neither visible in the template definition nor found by argument-dependent lookup
Test<V - 1>();
这是我在使用 GCC 的问题中提到的错误消息:
/home/liu/source/untitled4/main.cpp:7:14: error: no matching function for call to ‘Test<(1 - 1)>()’
Test<V - 1>();
而且我手上暂时没有Windows环境,如果MSVC报错我会稍后贴上。
虽然评论已经解决了问题——每个独立函数模板必须在使用前声明——关于差异的问题 可以简单地通过引用 [temp.class.spec.general]/7:
来回答Partial specialization declarations themselves are not found by name lookup. Rather, when the primary template name is used, any previously-declared partial specializations of the primary template are also considered. […]
因此,从 实例化点 可用的特化是可用的,因此可以在任何实例化之前自由地进行相互引用。 (这类似于查找 dependent 函数名称的规则。)