首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >确保模板参数类型与其可变构造函数的类型相匹配

确保模板参数类型与其可变构造函数的类型相匹配
EN

Stack Overflow用户
提问于 2019-05-26 14:35:22
回答 3查看 78关注 0票数 2

我希望有一个这样的类:

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_ifis_same中,还是通过类的初始化器列表并试图将内容存储到指针中。我不知道是否应该使用T数组,但是在将参数传递到构造函数之前,数组的大小是未知的。我还试图在不使用std::vector等基本容器的情况下实现这一点;它更多的是为了自我教育,而不是为了实用的源代码。我只想看看如何使用原始指针来实现这一点。

编辑

我已经将我的类改为如下所示:

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 arguments"
  • And第二个:C2440:”正在初始化,无法从初始化器列表转换为容器,没有构造函数可以采用源类型,或者构造函数重载解析不明确。“
EN

回答 3

Stack Overflow用户

发布于 2019-05-26 15:39:29

std::is_same只比较两种类型,不能使用包扩展来声明多个模板参数。这意味着您需要将所有的std::is_same检查都拉出到另一个检查中:

template <typename T, typename... Ts>
struct all_same : std::bool_constant<(std::is_same<T, Ts>::value && ...)> {};

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

    template <typename... Ts, std::enable_if_t<all_same<T, std::decay_t<Ts>...>::value>* = nullptr>
    Foo(Ts&&... ts)
        : data_{std::forward<Ts>(ts)...}
    {
    }
};

Live Demo

您还需要为data_数组分配内存。在这里,我使用了std::vector来为我处理这个分配,但是如果您真的想要的话,也可以使用new[]delete[]自己来管理它。

票数 2
EN

Stack Overflow用户

发布于 2019-05-26 16:02:27

enable_ifis_same不会在任何地方存储任何内容,它们只是编译时构造,不会对二进制可执行文件中的任何代码产生影响。

不管语法如何,您的代码实际上所做的是尝试获取构造函数参数的地址(这是一个临时参数)。一旦构造函数退出,这将是一个悬空指针。

要么Foo拥有内存区,并且必须在构造函数中分配,要么在析构函数中删除(如果有任何疑问:使用std::vector!),或者它为一些外部内存设置了别名,并且必须接收指向该内存的指针。

现在关于语法:

  • std::is_same是一个提供value布尔常量的模板,使用方法如下:std::is_same<T1, T2>::value。或者,仅当常量表达式(第1个模板参数)为真时,才可以使用std::is_same_v<T1, T2>.
  • std::enable_if提供type类型成员。像使用std::enable_if<expr, T>::type一样使用它。如果expr为true,则typeT的类型定义。否则,它将不被定义,并产生替换失败。或者,您可以使用std::enable_if_t<expr, T>

你可以看看here,看看你的类似方法。

但是您也可以通过使用成员向量来简化这一切。在这种情况下,向量构造函数确保所有参数都具有兼容的类型。下面是一个完整的示例:

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

using namespace std;

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

    template<typename ...Ts>
    explicit Foo(Ts... ts) : data_{ ts... } {}

    void print() {
        for (const auto &v : data_) {
            cout << v << " ";
        }
        cout << endl;
    }
};

int main() {

    Foo<int> ints { 1, 2, 3, 4, 5 };
    Foo<string> strings { "a", "b", "c", "d", "e"};
    // Foo<string> incorrect { "a", 2, "c", 4, "e"};

    ints.print();
    strings.print();
    // incorrect.print();

    return 0;
}
票数 1
EN

Stack Overflow用户

发布于 2019-05-27 22:34:57

在C++17中,最常用的方法是使用std::cunjunction_v。它懒惰地计算后续值,并允许您避免使用折叠表达式。此外,对于您在编辑的代码片段中提到的两种情况,编译器生成的消息也是相同的。

此外,通过const-rvalue-ref传递数据也没有意义,因为不可能从const对象中移动数据。另外,你正在将一组参数移动到一个指针。我不知道该怎么做,所以就把它删除了。

另外,看看std::decay_t --如果没有它,它将无法工作,因为有时Ts不会被推断为int,而是const int &int &。这会导致std::is_same_v为false。

下面的代码在godbolt上编译得很好:

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

    template<
        typename... Ts,
        std::enable_if_t<
            std::conjunction_v<
                std::is_same<T, std::decay_t<Ts>>...
            >
        > * = nullptr
    >
    explicit Foo( Ts&&... ts ) : data_{ } {}
 };
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56311239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档