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

Accepting N arguments converting into the same type

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

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

// 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,2,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,3>(123,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;
};