微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

接受转换为相同类型的 N 个参数

如何解决接受转换为相同类型的 N 个参数

我目前正在尝试在 C++ 中创建一个 vector 类。 该类应该有一个构造函数,它接受与向量中的维度一样多的参数。维度在实例化向量时由模板定义。 所有的扩充都应该能够转换为向量源自的相同数据类型(在模板中定义)。

这是我到目前为止所写的(我在这里使用了许多其他问题的片段):

// this section is to create an typedef struct all_same which checks if all elements are of the same type

template<typename ...T>  // head template
struct all_same : std::false_type { };

template<>  // accept if no elements are present
struct all_same<> : std::true_type { };

template<typename T>  // accept if only one element is present
struct all_same<T> : std::true_type { };

template<typename T,typename ...Ts>  // check if first and second value are the same type and recurse
struct all_same<T,T,Ts...> : all_same<T,Ts...> { };



template<typename T,size_t N>
class vec_abs {
public:
    vec_abs(const vec_abs &vec);  // construct from another vector
    explicit vec_abs(const std::array<T,N> &arr);  // construct from array

    template<typename ...Ts> requires // only compile if:
            all_same<typename std::decay<Ts>::type...>::type  // all are the same type (this might be optional,no sure)
            && std::conjunction<std::is_convertible<Ts,T>...>::value &&  // all can be converted to T
            (sizeof(Ts) == N)  // there are N arguments
    explicit vec_abs(const Ts&&... values);  // construct from multiple arguments

private:
    std::array<T,N> data;
};

代码的第一部分测试所有参数是否都属于同一类型,取自此 question

我对这个解决方案不太确定(主要是因为它不起作用 :D),如果您有任何改进建议,我将不胜感激。

感谢您的帮助!

解决方法

递归模板非常昂贵(就编译时间和编译器内存使用而言),因此虽然它们可以工作,并且历史上是执行某些解决方案的唯一方法,但现在可以使用更现代的技术,这些技术更简洁并且可以编译快得多

您可以使用折叠表达式将整个 all_same 替换为简单的 constexpr 函数:

template <typename T,typename... Ts>
constexpr bool all_same() {
    return (std::is_same_v<T,Ts> && ...);
}

static_assert( all_same<int,int,int>() );

然而,鉴于它们都必须可以转换为 T,你为什么还要确保它们是完全相同的类型?这似乎是不必要的限制。您可以使用 std::is_convertible_v<From,To> 轻松地将上述函数更改为“all_convertible_to”。

,

如果您不希望所有参数都属于同一类型,您可以删除该部分。除此之外,您在这里有一个错字:

(sizeof(Ts) == N) 

应该

(sizeof...(Ts) == N) 

修复后,转发参数并添加构造函数的定义,您的代码似乎可以做您想要的:

#include <type_traits>
#include <array>
#include <iostream>

template<typename T,size_t N>
struct vec_abs {
    template<typename ...Ts> requires // only compile if:
            std::conjunction<std::is_convertible<Ts,T>...>::value &&  // all can be converted to T
            (sizeof...(Ts) == N)  // there are N arguments
    explicit vec_abs(Ts&&... values) : data({std::forward<Ts>(values)...}) {}
    std::array<T,N> data;
};

int main() {
    auto foo = vec_abs<int,3>(1,2,3);
    foo = vec_abs<int,3>(1.0,3);    
    for (const auto& e : foo.data) std::cout << e;

    auto bar = vec_abs<std::string,3>("foo",std::string{"bar"},"moo");
    for (const auto& e : bar.data) std::cout << e;
    // bar = vec_abs<std::string,3>(123,1.2); // error wrong number
    //bar = vec_abs<std::string,1.2,42); // error cannot be converted
}

Output:

123foobarmoo

如果你确实想要所有参数都是相同类型的约束...

正如其他答案所提到的,可以避免 all_same 中的递归。以下已经在 C++11 中工作。不幸的是,我再也找不到原始来源了。

template <typename T,typename...Ts>
struct all_same {
    static const bool value = std::is_same< all_same,all_same<Ts...,T>>::value;
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。