2016-03-30 9 views
2

Я пытаюсь скомпилировать эту программу (см вживой here):Почему конструктор param_type был бы явным для случайного распределения?

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 не помогает.

ответ

3

Это явное, потому что оно имеет аргументы по умолчанию. Любой конструктор, принимающий 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 не рекомендуется.

+0

По моему мнению, конструктор 'param_type' не имеет смысла иметь аргументы по умолчанию. Как правило, необходимость использования параметра param_type просто означает, что значения по умолчанию не применяются. Конструктор 'construct_from()', который вы создали, является хакерским, и да, мне нравится сложный C++-материал :) Я поставлю его в проект [Happy Hacking C++] (https://github.com/Lingxi-Li/Happy_Hacking_CXX). Но для практического использования я просто буду придерживаться 'decltype (...) :: param_type'. – Lingxi

 Смежные вопросы

  • Нет связанных вопросов^_^