接受 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
}
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;
};
我目前正在尝试用 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
}
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;
};