C++ 如何为创建静态和动态大小向量提供公共接口?
我目前有很多代码可以处理动态大小向量(例如C++ 如何为创建静态和动态大小向量提供公共接口?,c++,c++11,templates,c++14,sfinae,C++,C++11,Templates,C++14,Sfinae,我目前有很多代码可以处理动态大小向量(例如std::vector,Eigen::VectorXd,…),我希望它也可以处理静态大小向量(例如std::array,Eigen::Vector3d,…)。我的代码是针对TVector模板化的,它假定TVector只有size和操作符[]。但最大的问题是建筑 当涉及到静态和动态向量的构造时,没有共同点。我决定用以下假设函数替换对TVector构造函数的所有调用: template <typename TVector> TVector cre
std::vector
,Eigen::VectorXd
,…),我希望它也可以处理静态大小向量(例如std::array
,Eigen::Vector3d
,…)。我的代码是针对TVector
模板化的,它假定TVector
只有size
和操作符[]
。但最大的问题是建筑
当涉及到静态和动态向量的构造时,没有共同点。我决定用以下假设函数替换对TVector
构造函数的所有调用:
template <typename TVector>
TVector createVector(std::size_t sizeAtInitialization)
{
if (TVector has constructor taking an integral type)
return TVector(sizeAtInitialization);
else
return TVector(); // sizeAtInitialization ignored
}
模板
TVector createVector(标准::大小\u t大小初始化)
{
if(TVector的构造函数采用整型)
返回TVector(大小初始化);
其他的
返回TVector();//忽略了sizeAtInitialization
}
这样,对createVector
的一般调用将变成createVector(3)
或createVector(3)
这对我没有帮助,因为这两种向量类型都是默认可构造的
然而,我甚至不确定这样的事情是否可能发生
我研究了静态if和成员函数检测。这一切看起来都非常复杂,因为
static\u if
使用lambda,它必须返回到中间结果,必须已经构造好,我不确定它会导致任何结果。你可以使用std::is\u constructible
和一点sfinae和std::enable\u if
using namespace std;
template <class T>
using IntegerConstructible =
typename enable_if<is_constructible<T, int>::value, T>::type;
template <class T>
using NotIntegerConstructible =
typename enable_if<!is_constructible<T, int>::value, T>::type;
template<class T>
auto createVector(int size)
-> IntegerConstructible<T> {
return {size};
}
template<class T>
auto createVector(int size)
-> NotIntegerConstructible<T>{
return {};
}
int main(){
auto x = createVector<std::vector<int>>(3);
auto y = createVector<std::array<int,3>>(3);
return 0;
}
使用名称空间std;
模板
使用integerconstructable=
typename enable_if::type;
模板
使用NotIntegerConstructable=
typename enable_if::value,T>::type;
模板
自动创建向量(整数大小)
->整数可构造{
返回{size};
}
模板
自动创建向量(整数大小)
->非整数可构造{
返回{};
}
int main(){
auto x=createVector(3);
自动y=createVector(3);
返回0;
}
IntegerConstructible
和NotIntegerConstructible
是别名模板,只要可以(或不能)构造模板参数,就可以定义这些模板。定义时
IntegerConstructible=T
因此,两个createVector
函数中只有一个具有有效的返回类型,另一个不能调用。这允许编译器选择正确的重载。我喜欢SFINAE(+1代表Tim),但我认为标记分发对于此类问题更为清晰
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
T cVH (int size, std::true_type const &)
{ std::cout << "with size" << std::endl; return { size }; }
template <typename T>
T cVH (int, std::false_type const &)
{ std::cout << "without size" << std::endl; return { }; }
template <typename T>
T createVector (int size)
{ return cVH<T>(size, typename std::is_constructible<T, int>::type{}); }
int main()
{
auto x = createVector<std::vector<int>>(3); // print "with size"
auto y = createVector<std::array<int,3>>(3); // print "without size"
}
您可以创建一个类型trait,并为使用的每个类型定义它。然后,可以使用SFINAE评估该特性,以选择静态或动态初始化函数。@NathanOliver与为每种类型专门化
createVector
相比,这有什么好处吗?“只是好奇。”鲁道夫·邦杜利斯说,“我认为这样传播比较容易。现在,使用函数所需要做的就是添加适当的类型特征,而不必添加自己的函数专门化。但是作为Eigen::VectorXd
和Eigen::Vector3d
基础的Eigen::Matrix
模板类有一个带int参数的构造函数。
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename>
struct withSize;
template <typename T>
struct withSize<std::vector<T>>
{ using type = std::true_type; };
template <typename T, std::size_t N>
struct withSize<std::array<T, N>>
{ using type = std::false_type; };
// others specializations of withSize for Eigen::Vector3d, Eigen::Matrix, etc.
template <typename T>
T cVH (int size, std::true_type const &)
{ std::cout << "with size" << std::endl; return { size }; }
template <typename T>
T cVH (int, std::false_type const &)
{ std::cout << "without size" << std::endl; return { }; }
template <typename T>
T createVector (int size)
{ return cVH<T>(size, typename withSize<T>::type{}); }
int main()
{
auto x = createVector<std::vector<int>>(3); // print "with size"
auto y = createVector<std::array<int,3>>(3); // print "without size"
}