我想要一个像这样的课程:
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
之类的基本容器来执行此操作;它更多是用于自我教育,而不是实用的源代码。我只想看看如何使用原始指针来完成此操作。
修改
我已经将班级更改为以下内容:
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
:“正在初始化,无法从初始值设定项列表转换为Container,没有构造函数可以采用源类型,或者构造函数重载解析度不明确。” 答案 0 :(得分:4)
为什么不简单地使用max_execution_time = 600
max_input_time = 600
memory_limit = 1024M
post_max_size = 1024M
?
max_allowed_packet = 1024M
如果某些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;
}
不同,则会出现编译时错误。
使用
Ts
您得到:
T
错误:内部将“ 5.0e + 0”的转换范围从“ double”缩小为“ int” {} [-Wnarrowing] Foo f1 {1、3、5、7}; ^
和
gcc -std=c++17 prog.cpp
您得到
错误:调用‘Foo :: Foo(int,int, double,int)’Foo f2(1、3、5、7); ^ note:候选人:“ template Foo :: Foo(Ts ...)”显式Foo(Ts ... ts): Foo(std :: initializer_list {ts ...})
...
更新:如果您真的想使用原始指针之类的示例,请参见以下完整示例:
Foo<int> f1{1, 3, 5., 7};
我让您用原始指针代替所有其他工作来替换unique_ptr:delete []等...
答案 1 :(得分:2)
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)...}
{
}
};
您还需要为data_
数组分配内存。在这里,我使用std::vector
来照顾我的分配,但是如果您确实愿意,可以使用new[]
和delete[]
自己进行管理。
答案 2 :(得分:1)
enable_if
和is_same
不会在任何地方存储任何内容,它们只是编译时构造,不会产生二进制可执行文件中的任何代码。
不管语法如何,您的代码本质上是在尝试获取构造函数参数的地址(这是临时的)。构造函数退出后,这将是一个悬空指针。
要么Foo
拥有内存区域,并且必须在构造函数中分配并在析构函数中删除(如有疑问:请使用std::vector
!),否则它会别名一些外部内存,并且必须接收一个指向该内存的指针。记忆。
现在有关语法:
std::is_same
是一个提供value
布尔常量的模板,其用法如下:std::is_same<T1, T2>::value
。或者,您可以使用std::is_same_v<T1, T2>
。std::enable_if
仅在常量表达式(第一个模板参数)为true时提供type
类型的成员。像std::enable_if<expr, T>::type
一样使用它。如果expr
为true,则type
是T
的typedef。否则,它不会被定义并产生替换失败。或者,您可以使用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;
}
答案 3 :(得分:0)
在C ++ 17中,最惯用的方法是使用std::cunjunction_v
。它懒惰地评估后续值,并允许您避免折叠表达式。对于您在已编辑的代码段中提到的两种情况,编译器生成的消息也是相同的。
此外,通过const-rvalue-ref传递数据没有任何意义,因为不可能从const对象中移动数据。另外,您正在将参数打包移动到指针。我不知道该怎么办,因此将其删除。
另外,请看一下std::decay_t
-没有它就无法正常工作,因为有时Ts
不是推导为int
而是推导为const int &
或{{1 }}。这导致int &
为假。
下面的代码可以在Godbolt上很好地编译:
std::is_same_v