为什么 param_type 构造函数对于随机分布是显式的?
Why would the param_type constructor be explicit for a random distribution?
我正在尝试编译这个程序(实时查看 here):
int main() {
std::random_device engine;
std::uniform_int_distribution<size_t> dis;
std::cout << dis(engine, {0, 5}) << std::endl;
}
但失败并显示错误消息:
error: converting to 'const std::uniform_int_distribution<long unsigned int>::param_type' from initializer list would use explicit constructor 'std::uniform_int_distribution<_IntType>::param_type::param_type(_IntType, _IntType) [with _IntType = long unsigned int]'
std::cout << dis(engine, {0, 5}) << std::endl;
很明显,是param_type
的显式构造函数阻止了我们这样做。但为什么首先将其指定为明确的呢?如果必须写的话,那是冗长和愚蠢的
std::cout << dis(engine, decltype(dis)::param_type(0, 5)) << std::endl;
有什么解释吗?而且,考虑到 param_type
构造函数在标准中是显式的,我怎样才能以简洁优雅的方式实现我想要的?请注意,在实践中,每次调用 dis
时范围可能不同。因此,在 dis
的构造时提供一个范围没有帮助。
它是显式的,因为它有默认参数。任何采用 1 个参数但不打算成为转换构造函数的构造函数都应该是显式的。
因为标准要求一个构造函数有两个默认参数,所以所有情况都是显式的。一种改进是强制使用一个非显式的 2 参数构造函数、一个显式的 1 参数构造函数和一个非显式的 0 参数构造函数。但是那艘船已经起航了。
我们可以解决您的问题。
template<class...Args>
struct construct_params_t {
std::tuple<Args&&...> data;
construct_params_t(Args&&...args):data(std::forward<Args>(args)...){}
private:
template<class T, std::size_t...Is>
T create( std::index_sequence<Is...> ){
return T( std::get<Is>(std::move(data))... );
}
public:
template<class T>
operator T()&&{
return create<T>( std::index_sequence_for<Args...>{} );
}
};
template<class...Args>
construct_params_t<Args...> construct_from(Args&&...args) {
return {std::forward<Args>(args)...};
}
现在你可以做:
int main() {
std::random_device engine;
std::uniform_int_distribution<size_t> dis;
std::cout << dis(engine, construct_from(0, 5)) << std::endl;
}
基本上,construct_from(a,b,c)
几乎可以用来构造任何东西,而且它是明确地这样做的,在构造它时不必提及它的名字。
如此构建的对象必须是可移动的,并且使用 RVO 省略它实际上不应该移动它们。
不建议存储 construct_from
的 return 值。
我正在尝试编译这个程序(实时查看 here):
int main() {
std::random_device engine;
std::uniform_int_distribution<size_t> dis;
std::cout << dis(engine, {0, 5}) << std::endl;
}
但失败并显示错误消息:
error: converting to 'const std::uniform_int_distribution<long unsigned int>::param_type' from initializer list would use explicit constructor 'std::uniform_int_distribution<_IntType>::param_type::param_type(_IntType, _IntType) [with _IntType = long unsigned int]'
std::cout << dis(engine, {0, 5}) << std::endl;
很明显,是param_type
的显式构造函数阻止了我们这样做。但为什么首先将其指定为明确的呢?如果必须写的话,那是冗长和愚蠢的
std::cout << dis(engine, decltype(dis)::param_type(0, 5)) << std::endl;
有什么解释吗?而且,考虑到 param_type
构造函数在标准中是显式的,我怎样才能以简洁优雅的方式实现我想要的?请注意,在实践中,每次调用 dis
时范围可能不同。因此,在 dis
的构造时提供一个范围没有帮助。
它是显式的,因为它有默认参数。任何采用 1 个参数但不打算成为转换构造函数的构造函数都应该是显式的。
因为标准要求一个构造函数有两个默认参数,所以所有情况都是显式的。一种改进是强制使用一个非显式的 2 参数构造函数、一个显式的 1 参数构造函数和一个非显式的 0 参数构造函数。但是那艘船已经起航了。
我们可以解决您的问题。
template<class...Args>
struct construct_params_t {
std::tuple<Args&&...> data;
construct_params_t(Args&&...args):data(std::forward<Args>(args)...){}
private:
template<class T, std::size_t...Is>
T create( std::index_sequence<Is...> ){
return T( std::get<Is>(std::move(data))... );
}
public:
template<class T>
operator T()&&{
return create<T>( std::index_sequence_for<Args...>{} );
}
};
template<class...Args>
construct_params_t<Args...> construct_from(Args&&...args) {
return {std::forward<Args>(args)...};
}
现在你可以做:
int main() {
std::random_device engine;
std::uniform_int_distribution<size_t> dis;
std::cout << dis(engine, construct_from(0, 5)) << std::endl;
}
基本上,construct_from(a,b,c)
几乎可以用来构造任何东西,而且它是明确地这样做的,在构造它时不必提及它的名字。
如此构建的对象必须是可移动的,并且使用 RVO 省略它实际上不应该移动它们。
不建议存储 construct_from
的 return 值。