此代码导致gcc6出错(但在gcc 4.8,5.2和clang 3.6中工作正常):
template <typename T>
struct outer
{
template <typename U>
struct inner
{
};
};
template <typename T>
struct is_inner_for
{
template <typename Whatever>
struct predicate
{
static constexpr bool value = false;
};
template <typename U>
struct predicate<typename outer<T>::template inner<U>>
{
static constexpr bool value = true;
};
};
static_assert(
is_inner_for<int>::template predicate<
outer<int>::inner<double>
>::value,
"Yay!"
);
错误是:
main.cpp:22:9: error: template parameters not deducible in partial specialization:
struct predicate<typename outer<T>::template inner<U>> : std::true_type
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:22:9: note: 'U'
^~~~~~~~~~~~~
命令行是:
g++ -std=c++1y -c main.cpp
我已在此处提交了一份关于gcc的错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70141
然而它被标记为无效(我错误地认为)。 outer<T>
中使用的predicate
在此时是具体类型,因此它不是非推断的上下文。
标准中是否存在阻止此c ++代码有效的内容?
答案 0 :(得分:3)
我怀疑这是gcc 6.0中的一个错误,并且在clang 3.9中出现了错误警告(警告很奇怪 - 因为警告意味着不会选择部分特化,但如果没有选择,静态断言就会触发)。
来自[temp.class.spec.match]:
如果是模板参数,则部分特化匹配给定的实际模板参数列表 可以从实际模板参数列表中推导出部分特化
我们可以从U
推断typename outer<T>::template inner<U>
中的outer<int>::inner<double>
吗?
来自[temp.deduct.type]:
如果模板参数仅在非推导中使用 上下文并未明确指定,模板参数推断失败。
未推断的背景是:
- 使用 qualified-id 指定的类型的嵌套名称说明符。
- [...]
但嵌套名称指定的在这里是typename outer<T>
,它不包含我们尝试推断的类型。其他非推断的上下文均不适用。所以演绎应该在这里取得成功。
考虑以下等效情况:
#include <utility>
template <class >
struct outer
{
template <class U> struct inner {};
};
template <class T>
struct bar {
template <class U> std::false_type foo(U const&);
template <class U> std::true_type foo(typename outer<T>::template inner<U> const&);
};
int main() {
static_assert(decltype(bar<int>{}.foo(outer<int>::inner<double>{}))::value, "!");
}
gcc 6.0和clang 3.9都会在没有警告的情况下编译此代码 - 但这与原始示例中的部分特化中会发生相同的推论。