C++ C++;主、模板化、专门化和别名模板参数的模板专门化
我正在尝试专门化一个模板,以便同时使用主类型、模板化类型和专门化/别名模板化类型。请参见下面的代码示例 它编译但不链接 如何为C++ C++;主、模板化、专门化和别名模板参数的模板专门化,c++,templates,c++17,template-meta-programming,template-specialization,C++,Templates,C++17,Template Meta Programming,Template Specialization,我正在尝试专门化一个模板,以便同时使用主类型、模板化类型和专门化/别名模板化类型。请参见下面的代码示例 它编译但不链接 如何为zero()编写一个模板专门化,我可以将其称为zero(),并且仍然能够调用zero等 原因是,在我的应用程序中,我没有得到myvec的大小N,因此我无法编写zero(),但是,我知道myvec是一个模板别名,如下所示,我知道模板的结构等,只是不知道大小: #include <iostream> #include <array> #include
zero()
编写一个模板专门化,我可以将其称为zero()
,并且仍然能够调用zero
等
原因是,在我的应用程序中,我没有得到myvec
的大小N
,因此我无法编写zero()
,但是,我知道myvec
是一个模板别名,如下所示,我知道模板的结构等,只是不知道大小:
#include <iostream>
#include <array>
#include <vector>
template<std::size_t N>
using vec_t = std::array<double, N>;
using v_t = std::vector<double>;
using v5_t = vec_t<5>;
// generic declaration
template<typename T> T zero();
// full specialization to double
template<> double zero() { std::cout << " -> Double\n"; return 0;}
// full specialization to v_t
template<> v_t zero() { std::cout << " -> vector<double>\n"; return v_t{}; };
// full specialization to v5_t
template<> v5_t zero() { std::cout << " -> vec_t<5>\n"; return v5_t{}; };
// attempt at partial specialization to vec_t<N>
template<template<typename T, std::size_t N> typename V, typename T, std::size_t N> V<T, N> zero() {
std::cout << " -> V<T, N>\n";
return V<T, N>{};
};
template<template<std::size_t N> typename V, std::size_t N> V<N> zero() {
std::cout << " -> V<N>\n";
return V<N>{};
};
int main() {
double z1 = zero<double>(); // works
v_t z2 = zero<v_t>(); // works
v5_t z3 = zero<v5_t>(); // works
const std::size_t N = 6;
vec_t<N> z4 = zero<std::array, double, N >(); // works, but requires full specs of vec_t
vec_t<N> z5 = zero<vec_t, N>(); // works, but requires N
using myvec = vec_t<6>;
myvec z6 = zero<myvec>(); // linker error ! but is what I'd like to write
return 0;
}
#包括
#包括
非常感谢你的帮助!(P.S.解决方案到CPP17是好的)< P>您在C++中使用部分专用化但部分专业化是不允许的,在C++中。
但是对于类是允许的,因此,如果可以用模板类中的方法替换zero()
模板函数,则可以编写如下内容
#include <iostream>
#include <array>
#include <vector>
template<std::size_t N>
using vec_t = std::array<double, N>;
using v_t = std::vector<double>;
using v5_t = vec_t<5>;
// generic declaration
template <typename T>
struct zero;
// specializations
template <>
struct zero<double>
{ double operator() () { std::cout << " -> double\n"; return {};} };
template <>
struct zero<v_t>
{ v_t operator() () { std::cout << " -> v_t\n"; return {};} };
template <>
struct zero<v5_t>
{ v5_t operator() () { std::cout << " -> v5_t\n"; return {};} };
template <std::size_t N>
struct zero<vec_t<N>>
{ vec_t<N> operator() () { std::cout << " -> vec_t + N\n"; return {};} };
template <template <std::size_t> class C, std::size_t N>
struct zero<C<N>>
{ C<N> operator() () { std::cout << " -> C + N\n"; return {};} };
int main() {
double z1 = zero<double>{}();
v_t z2 = zero<v_t>{}();
v5_t z3 = zero<v5_t>{}();
constexpr std::size_t N = 6;
vec_t<N> z4 = zero<std::array<double, N>>{}();
vec_t<N> z5 = zero<vec_t<N>>{}();
using myvec = vec_t<6>;
myvec z6 = zero<myvec>{}(); // now works
}
zero<double>();
zero<double>::func();
因为必须创建所需类型的对象,所以
// .........VV
zero<double>{}();
其中,double
专门化是
template <>
struct zero<double>
{ static double func () { std::cout << " -> double\n"; return {};} };
模板
结构零
{静态双FUNC(){STD::CUT您不希望在C++中使用部分专用化,但部分专门化是不允许的。
但是对于类是允许的,因此,如果可以用模板类中的方法替换
zero()
模板函数,则可以编写如下内容
#include <iostream>
#include <array>
#include <vector>
template<std::size_t N>
using vec_t = std::array<double, N>;
using v_t = std::vector<double>;
using v5_t = vec_t<5>;
// generic declaration
template <typename T>
struct zero;
// specializations
template <>
struct zero<double>
{ double operator() () { std::cout << " -> double\n"; return {};} };
template <>
struct zero<v_t>
{ v_t operator() () { std::cout << " -> v_t\n"; return {};} };
template <>
struct zero<v5_t>
{ v5_t operator() () { std::cout << " -> v5_t\n"; return {};} };
template <std::size_t N>
struct zero<vec_t<N>>
{ vec_t<N> operator() () { std::cout << " -> vec_t + N\n"; return {};} };
template <template <std::size_t> class C, std::size_t N>
struct zero<C<N>>
{ C<N> operator() () { std::cout << " -> C + N\n"; return {};} };
int main() {
double z1 = zero<double>{}();
v_t z2 = zero<v_t>{}();
v5_t z3 = zero<v5_t>{}();
constexpr std::size_t N = 6;
vec_t<N> z4 = zero<std::array<double, N>>{}();
vec_t<N> z5 = zero<vec_t<N>>{}();
using myvec = vec_t<6>;
myvec z6 = zero<myvec>{}(); // now works
}
zero<double>();
zero<double>::func();
因为必须创建所需类型的对象,所以
// .........VV
zero<double>{}();
其中,double
专门化是
template <>
struct zero<double>
{ static double func () { std::cout << " -> double\n"; return {};} };
模板
结构零
{static double func(){std::cout在@max66 answer之后,您可以保留原始API,但将调用委托给模板结构:
// generic declaration
template <typename T>
struct zero_s;
// specializations
template <>
struct zero_s<double> {
double operator() () {
std::cout << " -> double\n"; return {};
}
};
template <template <typename T, std::size_t> class C, typename T, std::size_t N>
struct zero_s<C<T, N>> {
C<Type, N> operator() () {
std::cout << " -> C<T, Size>, Size = " << N << "\n";
return {};
}
};
template <std::size_t N> struct zero_s<vec_t<N>> {
vec_t<N> operator() () {
std::cout << " -> vec_t + N: " << N << "\n"; return {};
}
};
// ...
//------------------------------------------------
// generic "zero" - still a free function
//------------------------------------------------
template<typename T, typename... Ts> T zero() {
return zero_s<T, Ts...>{}();
}
//泛型声明
模板
结构零度;
//专业
模板
结构零度{
双运算符(){
std::cout以下@max66答案您可以保留原始API,但将调用委托给模板结构:
// generic declaration
template <typename T>
struct zero_s;
// specializations
template <>
struct zero_s<double> {
double operator() () {
std::cout << " -> double\n"; return {};
}
};
template <template <typename T, std::size_t> class C, typename T, std::size_t N>
struct zero_s<C<T, N>> {
C<Type, N> operator() () {
std::cout << " -> C<T, Size>, Size = " << N << "\n";
return {};
}
};
template <std::size_t N> struct zero_s<vec_t<N>> {
vec_t<N> operator() () {
std::cout << " -> vec_t + N: " << N << "\n"; return {};
}
};
// ...
//------------------------------------------------
// generic "zero" - still a free function
//------------------------------------------------
template<typename T, typename... Ts> T zero() {
return zero_s<T, Ts...>{}();
}
//泛型声明
模板
结构零度;
//专业
模板
结构零度{
双运算符(){
再次感谢您提供的两个极好的答案。我非常喜欢可变模板解决方案;-)。
事实证明,对于所述的问题,有一个更简单的解决方案,尽管不太通用,但不需要用结构替换函数。只需在zero()的通用声明中添加一个定义,即change
template <typename T> T zero();
template T zero();
到
template T zero(){return{};};
代码编译和运行都很好。我觉得有一点解释我为什么要做这些愚蠢的事情是正确的:在我的应用程序中,我混合了不同大小的Eigen::Matrix、Eigen::Tensor等类型的对象(通过模板别名实现)主要标量类型。不幸的是,本征类型没有通过{}
进行标准零初始化,而是具有静态setZero()函数。上述解决方案允许我使用本征特定初始化作为标准,然后完全专用于标量类型
我更新了再次感谢您的两个优秀答案。我非常喜欢可变模板解决方案;-)。
事实证明,对于所述的问题,有一个更简单的解决方案,尽管不太通用,但不需要用结构替换函数。只需在zero()的通用声明中添加一个定义,即change
template <typename T> T zero();
template T zero();
到
template T zero(){return{};};
代码编译和运行都很好。我觉得有一点解释我为什么要做这些愚蠢的事情是正确的:在我的应用程序中,我混合了不同大小的Eigen::Matrix、Eigen::Tensor等类型的对象(通过模板别名实现)主要标量类型。不幸的是,本征类型没有通过{}
进行标准零初始化,而是具有静态setZero()函数。上述解决方案允许我使用本征特定初始化作为标准,然后完全专用于标量类型
我更新了谢谢你的回答。我之前也在考虑函数的部分专业化是禁止的问题。但是,函数的部分专业化应该会导致编译时错误,不是吗?我的代码是编译的,但没有链接。另外,请注意我是“专业化的”通过使用别名
。据我所知,这对编译器来说是透明的。对我来说,从z4
到z
的转换已经是一个局部特化-std:array,double被vec_t取代。似乎应该可以进行额外的步骤,同时去掉N。@JReichardt-你写的东西en不是部分专门化:是重载。但是,这样一来,你就不能按你想要的方式调用函数(zero
),你必须以zero()
的方式调用。链接器错误来自于zero()
匹配未定义的初始(通用)声明(所以编译)(所以链接错误)。似乎我对重载和专门化的确切区别感到困惑。你会说我重载了返回类型吗?Zero()不接受任何参数。总之,您是对的-定义泛型声明解决了问题-请参阅下面。再次感谢。专门化和重载之间的区别不容易在注释中解释…您的前三个专门化(double
,v\u t
和v5\u t
)是第一个声明的专门化,接收单个模板参数(类型名)。以下zero()
(V
和V
)基于不同的模板参数,因此与原始泛型声明不匹配