如何为所有“ std :: array”的工厂结构进行部分专业化,该结构超过4`元素



我想将呼叫从工厂功能模板派遣到基于返回类型的部分专业化的结构:

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

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>{};  
    }
};

您可以看到您的代码都与两个编译器一起编译。

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

最新更新