如何为所有具有超过 4 个元素的 std::array 部分特化工厂结构?

How to partially specialize a factory struct for all `std::array`s with more than `4` elements?

我想将调用从工厂函数模板分派到一个基于 return 类型部分特化的结构:

#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 > 4 启用模板。因此,如果 N == 5,此模板将变为 "visible",并且它肯定更适合调用

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

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

我不知道谁是对的(给出错误的 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>{};  
    }
};

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

您的模板类型与数组类型不匹配(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 {};
        }
    }
};