c++ - 确保模板参数类型与其可变构造函数的类型匹配

标签 c++ templates c++17 variadic-functions enable-if

我想要这样的类(class):

template<typename T>
struct Foo {
    T* data_;

    template<typename... Ts, std::enable_if<std::is_same<T,Ts>...>...>
    explicit Foo(Ts...ts) : data_{ ts... } {}
};

但是;语法有问题,我不确定在初始化时是否可以像这样直接将参数设置为指针。

我希望它做的只是这样:

Foo<int> f1{ 1, 3, 5, 7 }; // Or
// Foo<int> f1( 1, 3, 5 7 );
// f1.data_[0] = 1
// f1.data_[1] = 3
// f1.data_[2] = 5
// f1.data_[3] = 7
// f1.data_[4] = ... not our memory either garbage or undefined...

Foo<float> f2{ 3.5f, 7.2f, 9.8f }; // Or
// Foo<float> f2( 3.5f, 7.2f, 9.8f );
// f2.data_[0] = 3.5
// f2.data_[1] = 7.2
// f2.data_[2] = 9.8
// f2.data_[3] = ... not our memory

我还想让构造函数检查以确保传递给构造函数的每个参数都是 <T> 类型的;简单地把每个 Ts它必须是 T .

我可能想得太多了,但对于我来说,我无法得到这个或类似的东西来编译。不知道是不是在enable_if里面, is_same或者通过类的初始化列表并尝试将内容存储到指针中。我不知道我是否应该使用 T 的数组相反,在将参数传递给构造函数之前,数组的大小是未知的。我也尝试在不使用基本容器(例如 std::vector)的情况下执行此操作;它比实用的源代码更适合 self 教育。我只想看看如何使用原始指针完成此操作。


编辑

我把我的类(class)改成了这样:

template<typename T>
struct Foo {
    T* data_;

    template<typename... Ts, std::enable_if_t<std::is_same<T, Ts...>::value>* = nullptr>
    explicit Foo( const Ts&&... ts ) : data_{ std::move(ts)... } {}
 };

尝试使用它时:

 int a = 1, b = 3, c = 5, d = 7;
 Foo<int> f1( a, b, c, d );
 Foo<int> f2{ a, b, c, d };

这次迭代我更接近了一点;但它们都给出了不同的编译器错误。

  • 第一个是:C2661 : “没有重载函数需要 4 个参数”
  • 第二个:C2440 : “正在初始化,无法从初始化列表转换为容器,没有构造函数可以采用源类型,或者构造函数重载解析不明确。”

最佳答案

为什么不简单地使用 std::initialize_list:

#include <iostream>
#include <type_traits>
#include <vector>

template <class T>
struct Foo
{
  std::vector<T> data_;

  explicit Foo(std::initializer_list<T> data) : data_(data)
  {
    std::cout << "1";
  };

  template <typename... Ts,
            typename ENABLE=std::enable_if_t<(std::is_same_v<T,Ts> && ...)> >
  explicit Foo(Ts... ts) : Foo(std::initializer_list<T>{ts...})
  {
    std::cout << "2";
  }
};

int main()
{
  Foo<int> f1{1, 3, 5, 7}; // prints 1
  Foo<int> f2(1, 3, 5, 7); // prints 1 then 2

  return 0;
}

如果某些 TT 不同,您将遇到编译时错误。

gcc -std=c++17  prog.cpp  

你得到:

  Foo<int> f1{1, 3, 5., 7};

error: narrowing conversion of ‘5.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing] Foo f1{1, 3, 5., 7}; ^

Foo<int> f2(1, 3, 5., 7);

你得到了

error: no matching function for call to ‘Foo::Foo(int, int, double, int)’ Foo f2(1, 3, 5., 7); ^ note: candidate: ‘template Foo::Foo(Ts ...)’ explicit Foo(Ts... ts) : Foo(std::initializer_list{ts...})

...

更新:如果您真的想使用类似原始指针的东西,这里有一个完整的工作示例:

#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>

template <class T>
struct Foo
{
  size_t n_;
  std::unique_ptr<T[]> data_;

  explicit Foo(std::initializer_list<T> data) : n_(data.size()), data_(new T[n_])
  {
    std::copy(data.begin(), data.end(), data_.get());
    std::cout << "1";
  };

  template <typename... Ts, typename ENABLE = std::enable_if_t<(std::is_same_v<T, Ts> && ...)> >
  explicit Foo(Ts... ts) : Foo(std::initializer_list<T>{ts...})
  {
    std::cout << "2";
  }

  friend std::ostream& operator<<(std::ostream& out, const Foo<T>& toPrint)
  {
    for (size_t i = 0; i < toPrint.n_; i++)
      std::cout << "\n" << toPrint.data_[i];
    return out;
  }
};

int main()
{
  Foo<int> f1{1, 3, 5, 7};  // prints 1
  Foo<int> f2(1, 3, 5, 7);  // prints 1,2

  std::cout << f1;
  std::cout << f2;

  return 0;
}

我让您用原始指针替换 unique_ptr 并完成所有额外工作:delete[] 等...

关于c++ - 确保模板参数类型与其可变构造函数的类型匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56311239/

相关文章:

c++ - 为什么 GoogleMock 会泄露我的 shared_ptr?

c++ - 定义 typedef 的可变参数模板(使用 C++11)

c++ - constexpr if 和 static_assert

c++ - 具有三元运算符和模板的自动

c++ - 结构减去填充的编译时大小

c++ - 为什么不弹出窗口?

c++ - 被调用类中的 OpenMP 临界区(不同于并行循环)

c++ - 空指针不指向 cpp 中的 0x0 位置

c++ - 如何将文件系统路径转换为字符串

c++ - 引入typetraits后非模板的模板定义