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

How to provide a common interface for creation of static and dynamic size vectors?

我有很多代码目前可以使用 动态大小向量 (例如 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
}

这样,对 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;
}

IntegerConstructibleNotIntegerConstructible 是别名模板,只要可以(或不能)构造模板参数就可以定义它们。定义时 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"
 }