如何为所有具有超过 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>{};
}
};
您可以看到您的代码可以使用两种编译器进行编译。
您的模板类型与数组类型不匹配(int
与 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 {};
}
}
};
我想将调用从工厂函数模板分派到一个基于 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>{};
}
};
您可以看到您的代码可以使用两种编译器进行编译。
您的模板类型与数组类型不匹配(int
与 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 {};
}
}
};