【问题标题】:How to partially specialize a factory struct for all `std::array`s with more than `4` elements?如何为具有超过 4 个元素的所有 std::array 部分专门化工厂结构?
【发布时间】:2019-02-21 12:17:26
【问题描述】:

我想将工厂函数模板的调用分派到一个基于返回类型部分专门化的结构:

#include <array>

template<typename Type, typename Enable=void> 
struct make_it; 

template<typename A> 
struct make_it<std::array<A, 3>>
{
    static std::array<A, 3> apply()
    {
        return {A{0}, A{1}, A{2}}; 
    }
};

template<typename A> 
struct make_it<std::array<A, 4>>
{
    static std::array<A, 4> apply()
    {
        return {A{0}, A{0}, A{0}, A{0}}; 
    }
};

template<typename T> 
constexpr bool greater(T&& a, T&& b)
{
    return a > b;
}

template<typename T, int N> 
struct make_it<std::array<T, N>, std::enable_if_t<greater(N,4)>>
{
    static std::array<T, N> apply()
    {
        return std::array<T,N>{};  
    }
};

template<typename Type> 
Type make()
{
    return make_it<Type>::apply(); 
}

int main()
{
    auto a = make<std::array<double,3>>(); 
    auto b = make<std::array<double,4>>(); 
    auto c = make<std::array<double,5>>();
}

编译

g++  -O3 -std=c++2a -Wall -Wpedantic -Wunused-parameter -I /usr/include main.cpp -o main

使用g++ (GCC) 8.2.1 20181127 会导致错误

main.cpp: In instantiation of ‘Type make() [with Type = std::array<double, 5>]’:
main.cpp:49:41:   required from here
main.cpp:42:32: error: incomplete type ‘make_it<std::array<double, 5>, void>’ used in nested name specifier
     return make_it<Type>::apply();

SFINAE 线有问题吗

struct make_it<std::array<T, N>, std::enable_if_t<greater(N,4)>>

我认为这应该部分专门化 make_it,为所有 N &gt; 4 启用模板。所以如果N == 5,这个模板就会变得“可见”,它肯定更适合调用

auto c = make<std::array<double,5>>();

比不完整的类型?这里发生了什么?

【问题讨论】:

  • 我猜您使用的是greater,因为&lt;N &gt; 4&gt; 会混淆解析器,但您可以改用&lt;(N &gt; 4)&gt;
  • @Quentin:谢谢这摆脱了greater,但错误仍然存​​在。
  • 请注意Clang compiles this fine。这可能需要语言律师!
  • @Quentin:好的,谢谢!
  • 我相信这可以简化为template&lt;class&gt; struct A; template&lt;class T, int N&gt; struct A&lt;std::array&lt;T, N&gt;&gt; {}; A&lt;std::array&lt;int, 4&gt;&gt; a;

标签: c++ templates sfinae template-specialization


【解决方案1】:

我不知道谁是对的(给出错误的 g++ 或编译的 clang++)但我看到在您的代码中存在缺陷:您截取了 std::array 的大小,即 std::size_t,所以一个无符号整数,如int,一个有符号整数。

如果你编写截取正确类型的值的偏特化,std::size_t

// ..................VVVVVVVVVVV  (not int)
template<typename T, std::size_t N> 
struct make_it<std::array<T, N>, std::enable_if_t<(N > 4)>>
{
    static std::array<T, N> apply()
    {
        return std::array<T,N>{};  
    }
};

或者也可以作为auto,如果你可以使用C++17,

// ..................VVVV
template<typename T, auto N> 
struct make_it<std::array<T, N>, std::enable_if_t<(N > 4)>>
{
    static std::array<T, N> apply()
    {
        return std::array<T,N>{};  
    }
};

您可以看到您的代码使用两种编译器进行编译。

【讨论】:

    【解决方案2】:

    您的模板类型与数组类型不匹配(intstd::size_t)。

    作为替代方案,当您使用 C++17 时,您可以使用:

    template<typename T, std::size_t N> 
    struct make_it<std::array<T, N>>
    {
        static_assert(N >= 3); // As you don't provide specialization for those cases.
    
        static std::array<T, N> apply()
        {
            if constexpr(N == 3) {
                return {{T(0), T(0), T(0)}};
            } else if constexpr(N == 4) {
                return {{T(0), T(0), T(0), T(0)}};
            } else if constexpr(N > 4) {
                return {};
            }
        }
    };
    

    【讨论】:

      猜你喜欢
      • 2021-10-15
      • 2012-09-25
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多