【问题标题】:Auto non-type template parameter: ambiguous partial specializations in Clang自动非类型模板参数:Clang 中不明确的偏特化
【发布时间】:2019-10-01 05:00:44
【问题描述】:

Clang(7, 8, trunk) 拒绝以下代码

enum class E {};
inline static constexpr auto e = E{};
// inline static constexpr auto e = nullptr;

template<auto, int> class S;
template<int a, int b> class S<a, b> {};
template<int b> class S<e, b> {};

int main() {
    S<0, 0> s;
}

出现错误:

error: ambiguous partial specializations of 'S<0, 0>'
note: partial specialization matches [with a = 0, b = 0]
template<int a, int b> class S<a, b> {};
                             ^
note: partial specialization matches [with b = 0]
template<int b> class S<e, b> {};
                      ^
  1. 为什么会模棱两可? e 怎么能匹配 0?如果我用nullptr 替换E{},Clang 停止抱怨。这看起来像 Clang 的错误。 GCC 编译它就好了。

  2. 如果是错误,有什么解决方法?在我的例子中,auto 参数可以是E(并且只有一个值E{})或int。那么:

    template<auto, int, typename> class S_impl;
    template<int a, int b> class S_impl<a, b, int> {};
    template<int b> class S_impl<e, b, E> {};
    
    template<auto a, int b> using S = S_impl<a, b, decltype(a)>;
    

    还有更简洁的方法吗?

【问题讨论】:

    标签: c++ templates clang c++17 auto


    【解决方案1】:

    Clang 的推论是错误的。它类似于this bug,链接到此question(与您在模板参数中使用 auto 不完全相同,这将阻止您使用 stdc++14 进行编译)。

    一个有趣的例子是,如果它是一个完整的专业化,情况就不是这样了。仅适用于部分专业化:

    #include <iostream>
    
    enum class E {};
    inline static constexpr auto e = E{};
    
    template <auto a, int b>
    class FOO;
    template <int a, int b > class FOO<a, b> {};
    template <int b> class FOO<e, b> {};
    
    template <auto a, int b>
    class BAR;
    template <int a, int b > class BAR<a, b> {};
    template <> class BAR<e, 0> {};
    
    template <auto a>
    class BAZ;
    template <int a> class BAZ<a> {};
    template <> class BAZ<e> {};
    
    int main() {
        // FOO <0, 0> foo; // <= Not Ok
        BAR<0, 0> bar; // <= Ok
        BAZ<0> baz; // <= Ok
    }
    

    任何强制扣除类型模板参数的解决方案都将起作用,因此您建议的解决方案是完全有效的。恕我直言,当不需要提高可读性时,我会避免在模板参数中使用 auto :

    template <typename T, T value, int> class S_impl; // <= this auto is not necessary
    template <int a, int b> class S_impl<int, a, b> {};
    template <int b> class S_impl<E, e, b> {};
    // Either define S to use S<0,0> or directly use S_impl<int, 0, 0>
    template <auto a, int b> using S = S_impl<decltype(a), a, b> // <= this auto is necessary
    

    【讨论】:

      猜你喜欢
      • 2016-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多