Код проще лямбды для вызова в конструкторе, который использует функцию выходного параметра для инициализации константного члена
В шапке у меня есть
class CSomeClass
{
const GUID m_guid;
public:
CSomeClass();
///...
}
И в исходном файле
CSomeClass::CSomeClass()
, m_guid(
[]() {
GUID g;
::CoCreateGuid(&g);
return g;
}()
)
{
}
Как вы знаете, руководства могут быть использованы в качестве идентификаторов, которые не должны быть изменены. Учитывая ::CocreateGuid()
Функция предоставляет то, что я хочу в качестве выходного параметра, вместо того, чтобы возвращать его, я не могу напрямую использовать простой вызов функции для инициализации поля члена m_guid, который является константой.
Таким образом, следствием его константности является то, что он должен быть инициализирован перед открывающей скобкой в списке инициализаторов и, следовательно, не может быть просто назначен вызовом ::CocreateGuid()
в теле конструктора.
Есть ли более простой способ инициализировать его, чем это лямбда-выражение?
5 ответов
Когда лямбда-выражение является правильным, я бы использовал вспомогательную функцию для этого:
GUID create_guid()
{
GUID g;
::CoCreateGuid(&g);
return g;
}
CSomeClass::CSomeClass() : m_guid(create_guid()) {}
К тому же, create_guid()
имеет значение само по себе и может быть использовано повторно (даже если возможно сделать / исправить детали реализации).
Вы должны рассмотреть оборачивание GUID в его собственный класс:
class CGUID
{
public:
CGUID()
{
CoCreateGuid(m_guid);
}
const GUID& guid() const { return m_guid; }
// Maybe some useful functions:
bool operator==(const CGUID&) const;
private:
GUID m_guid;
};
Теперь вы можете использовать вышеуказанное в качестве участника:
class CSomeClass
{
const CGUID m_guid;
...
Здесь мы абстрагируем ваш шаблон:
template<class A>
A co_make( HRESULT(*f)(A*) {
A a;
HRESULT hr = f(&a);
Assert(SUCCEEDED(hr));
if (!SUCCEEDED(hr))
throw hr;
return a;
}
CSomeClass::CSomeClass()
m_guid(
co_make(&::CoCreateGuid)
)
{}
где мы обнаруживаем неудачу и утверждаем, а затем бросаем, если это так.
Я не уверен, что это проще.
На самом деле, написать GUID make_guid()
функции, вставьте его в какой-то заголовок и вызовите его.
Ваше предложение - это самый простой способ инициализации константы-члена экземпляра.
Не пугайтесь лямбда-выражений, вообще-то, как правило, это новая рекомендация стиля использовать лямбда-выражения для сложных инициализаций констант и ссылок, потому что они имеют свойство только инициализироваться в точке объявления (или члена экземпляра). инициализация в списке инициализаторов).
Кроме того, ваш код вызывает "оптимизацию именованного возвращаемого значения", и при возврате из лямбды нет конструкции копирования.
Интерфейс CoCreateGuid имеет недостатки, поскольку требует выходного аргумента.
Если вы настаиваете на том, чтобы не использовать лямбду, я думаю, что следующая наиболее практичная альтернатива - деконтифицировать в теле конструктора const_cast
передать его CoCreateGuid.
Имейте в виду, что когда вы вводите тело конструктора, язык считает, что все отдельные элементы были правильно инициализированы, и будет вызывать деструкторы для них, если произойдет исключение, это очень сильно влияет на то, что что-то инициализируется в списке инициализаторов или осталось с двоичным шаблоном мусора.
Наконец, к сожалению, вы не можете просто позвонить CoCreateGuid с неконфиденциальной ссылкой на m_guid
в лямбда, потому что лямбда все равно будет возвращать значение, и это перезапишет член. По сути это то же самое, что вы уже написали (за исключением конструктора по умолчанию g
)
Было бы проще, если бы вы объявили m_guid
как mutable
член экземпляра, в отличие от const
, Разница в том, что mutable
как const
для пользователей класса, но прекрасно подходит для класса