У меня нет этого вопроса, вы спрашиваете, почему язык позволяет вам делать:
template <typename T, typename U>
auto foo( X<T> lhs, X<U> rhs ) -> decltype( lhs + rhs );
Вместо принуждение к искусственному добавлению статического фиктивного члена в шаблон X
, чтобы вы могли ввести:
template <typename T, typename U>
decltype( X<T>::unneeded_artificial_static_member +
X<U>::unneeded_artificial_static_member )
foo( X<T> lhs, X<U> rhs ) -> decltype( lhs + rhs );
Серьезно? Я имею в виду, что вы можете использовать другие менее обременительные конструкции, например:
template <typename T>
T& lvalue_of();
template <typename T, typename U>
decltype( lvalue_of< X<T> > + lvalue_of< X<U> > )
foo( X<T> lhs, X<U> rhs );
А затем вынудите использовать определенные варианты lvalue_of
при необходимости:
template <typename T, typename U>
decltype( lvalue_of< X<T> > + lvalue_of< X<U> const > )
foo( X<T> lhs, X<U> const & rhs );
А затем создайте дополнительные варианты для rvalue_ref
... для каждого потенциального варианта использования, который может возникнуть, но с какой стати вы бы предпочли, чтобы стандарт заставлял вас подвергаться таким странным ошибкам (не забудьте обновить decltype
если вы изменяете аргумент?) Конструкции для определения типа, когда после объявления аргумента компилятор может так легко сделать это самому безопасным простым безопасным способом?
С этой линией рассуждений вы также должны полностью исключить лямбды из языка, они вообще не являются вспомогательной функцией. Возможность включения была возможность использовать локальный класс в шаблоне:
std::function< void () > f = [](){ std::cout << "Hi"; };
может быть легко реализовано как:
struct lambda {
void operator()() {
std::cout << "Hi";
}
};
std::function< void () > f = lambda();
И тогда вы, вероятно, можете подумать о большом количестве других функций, которые так же легко можно исключить из языка, поскольку есть обходные пути.