如何为创建静态和动态大小向量提供通用接口?

时间:2017-01-26 17:12:00

标签: c++ c++11 templates c++14 sfinae

我有很多代码目前适用于动态尺寸向量(例如std::vectorEigen::VectorXd,...),我希望它能够工作使用静态大小向量(例如std::arrayEigen::Vector3d,...)。我的代码在TVector方面被模板化,假设TVector只有sizeoperator[]。但最大的问题是建设

在构建静态和动态向量时,没有共同点。我决定用以下假设函数替换对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
}

这样对[{1}}的通用调用将变为createVector<TVector>createVector<std::vector<double>>(3)

std::is_default_constructible在这里不会帮助我,因为两种矢量类型都是默认可构造的。

然而,我不确定这样的事情是否可能。

我研究了静态if here成员函数检测 here。这一切看起来都非常复杂,因为createVector<std::array<double, 3>>(3)使用的lambda必须返回到必须已经构造的中间结果,我不确定它是否会导致任何结果。

2 个答案:

答案 0 :(得分:2)

您可以将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;
}

IntegerConstructibleNotIntegerConstructible是别名模板,只要模板参数可以(或不能构造),就可以定义它们。定义时 IntegerConstructible<T> = T

因此,只有两个createVector函数中只有一个具有有效的返回类型,另一个函数无法调用。这允许编译器选择正确的重载。

答案 1 :(得分:1)

我喜欢SFINAE(Tim为+1),但我认为此类问题的标签调度更清晰

#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"
 }

---编辑---

如果没有可以为所有眼睛选择正确值的类型特征,您可以自己创建一个(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"
 }