对于曾经在gcc5中工作的情况,模板参数在gcc6中的部分特化中不可推导

时间:2016-03-08 19:04:05

标签: c++ templates gcc language-lawyer

此代码导致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

请参阅godbolt output here

我已在此处提交了一份关于gcc的错误报告:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70141

然而它被标记为无效(我错误地认为)。 outer<T>中使用的predicate在此时是具体类型,因此它不是非推断的上下文。

标准中是否存在阻止此c ++代码有效的内容?

1 个答案:

答案 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都会在没有警告的情况下编译此代码 - 但这与原始示例中的部分特化中会发生相同的推论。