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

标签 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 个参数但不打算成为转换构造函数的构造函数都应该是显式的。

因为标准要求一个构造函数有两个默认参数,所以所有情况都是显式的。一种改进是强制使用一个非显式的 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 的返回值。

关于c++ - 为什么 param_type 构造函数对于随机分布是显式的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36310098/

相关文章:

c++ - 使用 C++ 和 STL 的 vector 元素乘积

c++ - MySQL Connect/C++ 64 位构建错误

c++ - 因为 std::swap(s1, s2) 就足够了,所以 string::swap 可以忽略吗?

c++ - 如何正确找出lambda的返回类型

c++ - 当以相同方式调用时,函数的 Constexpr 版本会给出不同的结果

c++ - 将流运算符 >> 评估为 bool 值

c++ - 如何正确 "perfect forward"getter 函数?

c++ - 如何从 ListView 中获取项目以在组合框中使用它们

c++ - 为什么在 C++11 中使用非成员开始和结束函数?

c++ - result_of 用于具有 cv 限定参数的成员对象