Is it possible to constrain the type of arguments in a variadic constructor?
是否可以约束变量构造函数中的参数类型?
I want to be able to express
我想要表达。
X x1(1,3,4);
X x2(3,4,5);
// syntax error: identifier 'Args'
class X {
template<int ... Args> X(Args...)
{
}
};
// this works but allows other types than int
class Y {
template<typename ... Args> Y(Args...)
{
}
};
edit to clarify intent:
编辑澄清意图:
What I want to achieve is to store data passed into a constructor (constants known at compile time) into a static array.
我想实现的是将传递给构造函数(编译时已知的常量)的数据存储到静态数组中。
so there are some other
还有其他的
template<int ...values>
struct Z
{
static int data[sizeof...(values)];
};
template<int ... values>
int Z<values...>::data[sizeof...(values)] = {values...};
and in the constructor of X I would like to use Z like this:
在X的构造函数中,我想这样用Z:
class X {
template<int ... Args> X(Args...)
{
Z<Args...>::data // do stuff with data
}
};
Is that possible, our do I have to use integer_sequence?
是否可能,我们是否需要使用integer_sequence?
4 个解决方案
#1
15
Since you have the following:
既然你有以下几点:
template<int... values>
struct Z
{
static int data[ sizeof...( values ) ];
};
template <int... values>
int Z<values...>::data[ sizeof...( values ) ] = { values... };
You can use std::integer_sequence<>
to pass in the ints to Z<>
:
可以使用std::integer_sequence<>将ints传递给Z<>:
struct X
{
template <int... values>
X( std::integer_sequence<int, values...> )
{
for ( int i{ 0 }; i < sizeof...( values ); ++i )
Z<values...>::data[ i ]; // do stuff with data
}
};
You can make yourself a helper type to make it easy to call the ctor:
你可以让自己成为一个助手类型,使它容易打电话给ctor:
template <int... values>
using int_sequence = std::integer_sequence<int, values...>;
Then you can instantiate your class like so:
然后你可以实例化你的类,比如:
int main()
{
X x( int_sequence<1, 3, 5>{} );
}
#2
15
You can use std::initializer_list
:
您可以使用std::initializer_list:
#include <iostream>
#include <initializer_list>
void myFunc(std::initializer_list<int> args)
{
for (int i: args) std::cout << i << '\n';
}
int main(){
myFunc({2,3,2});
// myFunc({2,"aaa",2}); error!
}
#3
1
You've updated your question to indicate that all you need is a compile-time std::integer_sequence
, which is great.
您已经更新了您的问题,以表明您所需要的是编译时std::integer_sequence,这很好。
But just for the sake of future readers who might come here looking for the answer, I'd like to also answer your original question "Is it possible to constrain the type of arguments in a variadic constructor?"
但是为了将来的读者,他们可能会来这里寻找答案,我也想回答你最初的问题“是否可能限制变量构造函数中的参数类型?”
Yes. One way (the best way? I'm not sure) is to SFINAE on an extra template parameter, like this:
是的。一种方法(最好的方法?我不确定)是SFINAE关于一个额外的模板参数,像这样:
struct X {
template<
class... TT,
class E = std::enable_if_t<(std::is_same_v<TT, int> && ...)>
>
X(TT... tt) {
// do stuff with the ints "tt..."
}
};
The && ...
is a fold-expression, new in C++17. If your compiler doesn't support fold-expressions, just replace that with a hand-rolled all_of
.
& &……是一个折叠表达式,在c++ 17中是新的。如果编译器不支持折叠表达式,只需用手工滚动的all_of替换它。
#4
-5
No, you can't constrain the type. You can use static_assert
though. Would be something like this:
不,您不能约束类型。您可以使用static_assert。会是这样的:
static_assert(std::is_same<int, Args>::value ..., "have to be ints.");
Have not tried to use an expansion in a static_assert
like that though. You may need a constexpr that returns bool or something.
还没有尝试在static_assert中使用这样的展开。您可能需要一个返回bool或其他东西的constexpr。
#1
15
Since you have the following:
既然你有以下几点:
template<int... values>
struct Z
{
static int data[ sizeof...( values ) ];
};
template <int... values>
int Z<values...>::data[ sizeof...( values ) ] = { values... };
You can use std::integer_sequence<>
to pass in the ints to Z<>
:
可以使用std::integer_sequence<>将ints传递给Z<>:
struct X
{
template <int... values>
X( std::integer_sequence<int, values...> )
{
for ( int i{ 0 }; i < sizeof...( values ); ++i )
Z<values...>::data[ i ]; // do stuff with data
}
};
You can make yourself a helper type to make it easy to call the ctor:
你可以让自己成为一个助手类型,使它容易打电话给ctor:
template <int... values>
using int_sequence = std::integer_sequence<int, values...>;
Then you can instantiate your class like so:
然后你可以实例化你的类,比如:
int main()
{
X x( int_sequence<1, 3, 5>{} );
}
#2
15
You can use std::initializer_list
:
您可以使用std::initializer_list:
#include <iostream>
#include <initializer_list>
void myFunc(std::initializer_list<int> args)
{
for (int i: args) std::cout << i << '\n';
}
int main(){
myFunc({2,3,2});
// myFunc({2,"aaa",2}); error!
}
#3
1
You've updated your question to indicate that all you need is a compile-time std::integer_sequence
, which is great.
您已经更新了您的问题,以表明您所需要的是编译时std::integer_sequence,这很好。
But just for the sake of future readers who might come here looking for the answer, I'd like to also answer your original question "Is it possible to constrain the type of arguments in a variadic constructor?"
但是为了将来的读者,他们可能会来这里寻找答案,我也想回答你最初的问题“是否可能限制变量构造函数中的参数类型?”
Yes. One way (the best way? I'm not sure) is to SFINAE on an extra template parameter, like this:
是的。一种方法(最好的方法?我不确定)是SFINAE关于一个额外的模板参数,像这样:
struct X {
template<
class... TT,
class E = std::enable_if_t<(std::is_same_v<TT, int> && ...)>
>
X(TT... tt) {
// do stuff with the ints "tt..."
}
};
The && ...
is a fold-expression, new in C++17. If your compiler doesn't support fold-expressions, just replace that with a hand-rolled all_of
.
& &……是一个折叠表达式,在c++ 17中是新的。如果编译器不支持折叠表达式,只需用手工滚动的all_of替换它。
#4
-5
No, you can't constrain the type. You can use static_assert
though. Would be something like this:
不,您不能约束类型。您可以使用static_assert。会是这样的:
static_assert(std::is_same<int, Args>::value ..., "have to be ints.");
Have not tried to use an expansion in a static_assert
like that though. You may need a constexpr that returns bool or something.
还没有尝试在static_assert中使用这样的展开。您可能需要一个返回bool或其他东西的constexpr。