Странная языковая проблема: CWG 1581 :
В пункте 15 [special] совершенно ясно, что специальные функции-члены определяются неявно только тогда, когда они используются в odr. Это создает проблему для константных выражений в неоцененных контекстах:
struct duration {
constexpr duration() {}
constexpr operator int() const { return 0; }
};
// duration d = duration(); // #1
int n = sizeof(short{duration(duration())});
Проблема здесь в том, что нам не разрешено неявно определять constexpr duration::duration(duration&&)
в этой программе, поэтому выражение в списке инициализатора не является константой выражением (потому что он вызывает функцию constexpr, которая не была определена), поэтому инициализированный скобками инициализатор содержит сужающее преобразование, поэтому программа плохо сформирована.
Если мы раскомментируем строку # 1, конструктор перемещения будет неявно определена и программа действительна. Это жуткое действие на расстоянии крайне неудачно. Реализации расходятся по этому вопросу.
Вы можете прочитать остальную часть описания проблемы.
Решение для этой проблемы было принято в P0859 в Альбукерке в 2017 году (после C ++ 17 поставляется). Эта проблема была блокирующей, поскольку оба имели возможность иметь constexpr std::swap
(решен в P0879 ) и constexpr std::invoke
(решен в P1065 , который также имеет примеры CWG1581), оба для C ++ 20.
Самым простым для понимания примером здесь, на мой взгляд, является код из сообщения об ошибке LLVM, указанного в P1065:
template<typename T>
int f(T x)
{
return x.get();
}
template<typename T>
constexpr int g(T x)
{
return x.get();
}
int main() {
// O.K. The body of `f' is not required.
decltype(f(0)) a;
// Seems to instantiate the body of `g'
// and results in an error.
decltype(g(0)) b;
return 0;
}
CWG1581 - все о , когда Определены функции-члены constexpr, а разрешение гарантирует, что они определяются только при использовании. После P0859 вышеупомянутое хорошо сформировано (тип b
равен int
).
Поскольку std::swap
и std::invoke
оба должны полагаться на проверку функций-членов (переместить конструирование / назначение в первом и вызовы оператора / суррогатные вызовы во втором), они оба зависели от разрешения Эта проблема.