如何提供用于创建静态和动态大小向量的通用接口?
How to provide a common interface for creation of static and dynamic size vectors?
我有很多代码目前可以使用 动态大小向量 (例如 std::vector
、Eigen::VectorXd
、...),我会喜欢它也适用于 静态大小向量 (例如 std::array
、Eigen::Vector3d
、...)。我的代码是关于 TVector
的模板化,它假设 TVector
只有 size
和 operator[]
。但最大的问题是施工.
在构建静态和动态向量方面没有共同点。我决定用以下假设函数替换对 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
}
这样,对 createVector<TVector>
的通用调用将变为 createVector<std::vector<double>>(3)
或 createVector<std::array<double, 3>>(3)
。
std::is_default_constructible 在这里对我没有帮助,因为这两种向量类型都是默认可构造的。
但是,我不确定这样的事情是否可能。
我研究了static if and member function detection here。这一切看起来都非常复杂,并且由于 static_if
使用 lambdas,它必须 return 到一个必须已经构建的中间结果,我不确定它会导致任何地方。
您可以将 std::is_constructible
与一些 sfinae 和 std::enable_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;
}
IntegerConstructible
和 NotIntegerConstructible
是别名模板,只要可以(或不能)构造模板参数就可以定义它们。定义时
IntegerConstructible<T> = T
.
所以两个 createVector
函数中只有一个具有有效的 return 类型,另一个无法调用。这允许编译器选择正确的重载。
我喜欢 SFINAE(Tim +1),但我认为 tag-dispatcing 对于这类问题更清晰
#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"
}
--- 编辑 ---
如果没有 type-traits 可以 select 您所有类型的正确值,您可以自己创建一个,如下 (struct withSize
)
#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"
}
我有很多代码目前可以使用 动态大小向量 (例如 std::vector
、Eigen::VectorXd
、...),我会喜欢它也适用于 静态大小向量 (例如 std::array
、Eigen::Vector3d
、...)。我的代码是关于 TVector
的模板化,它假设 TVector
只有 size
和 operator[]
。但最大的问题是施工.
在构建静态和动态向量方面没有共同点。我决定用以下假设函数替换对 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
}
这样,对 createVector<TVector>
的通用调用将变为 createVector<std::vector<double>>(3)
或 createVector<std::array<double, 3>>(3)
。
std::is_default_constructible 在这里对我没有帮助,因为这两种向量类型都是默认可构造的。
但是,我不确定这样的事情是否可能。
我研究了static if static_if
使用 lambdas,它必须 return 到一个必须已经构建的中间结果,我不确定它会导致任何地方。
您可以将 std::is_constructible
与一些 sfinae 和 std::enable_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;
}
IntegerConstructible
和 NotIntegerConstructible
是别名模板,只要可以(或不能)构造模板参数就可以定义它们。定义时
IntegerConstructible<T> = T
.
所以两个 createVector
函数中只有一个具有有效的 return 类型,另一个无法调用。这允许编译器选择正确的重载。
我喜欢 SFINAE(Tim +1),但我认为 tag-dispatcing 对于这类问题更清晰
#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"
}
--- 编辑 ---
如果没有 type-traits 可以 select 您所有类型的正确值,您可以自己创建一个,如下 (struct withSize
)
#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"
}