为什么param_type构造函数对于随机分布是显式的?

时间:2016-03-30 13:20:01

标签: c++ c++11 language-lawyer c++-standard-library explicit

我正在尝试编译此程序(请参见实时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 个答案:

答案 0 :(得分:3)

它是明确的,因为它有默认的参数。任何不打算成为转换构造函数的构造函数都应该是显式的。

因为标准要求一个带有两个默认参数的构造函数,所有情况都是显式的。一个改进是强制要求一个非显式的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)可用于构造几乎任何东西,并且它明确地这样做,而不必在构造它时提及它的名称。

Live example

这样构造的物体必须是可移动的,并且使用RVO省略它不应该实际移动它们。

不建议存储construct_from的返回值。