Подтвердить что ты не робот

Почему std:: result_of принимает (не связанный) тип функции как аргумент типа?

Я понимаю, почему такие вещи так, как они есть, вопросы обычно не самые лучшие, но есть много людей на SO, которые настроены на стандартные обсуждения в комитетах, поэтому я надеюсь, что на это можно ответить фактически, так как я законно любопытно что ответ есть.

В принципе, мне потребовалось много времени, чтобы выяснить, что происходит с подписью шаблона std::result_of в первый раз, когда я это увидел: я думал, что это совершенно новая конструкция параметров шаблона, которую я никогда раньше не видел.

template< class F, class... ArgTypes >
class result_of<F(ArgTypes...)>;

Подумав об этом некоторое время, я понял, что это на самом деле: F(ArgTypes...) - это тип функции, но не тип функции, результат которой оценивается (это просто F): это тип функции, принимающей аргументы ArgTypes... и возвращающий тип F.

Разве это... нечетно? Вид хаки? Кто-нибудь знает, когда комитет когда-либо обсуждал какие-либо альтернативы, например, следующее...

template< class F, class... ArgTypes >
class result_of<F, ArgTypes...>;

?

Я предполагаю, что возможны ситуации, когда вторая конструкция не может быть использована так же легко, как первая, но какие?

Я не пытаюсь судить об этом, но это просто то, что это было в первый раз запутано для меня в первый раз, когда я это увидел, поэтому мне любопытно, есть ли веские основания для этого. Я понимаю, что часть ответа может быть просто "потому что Boost сделала это" таким образом, но все же оставила оставшиеся (фактические) вопросы...

  • Есть ли техническая причина Boost для выбора этого синтаксиса для кодирования информации типа, а не для любой альтернативы?

  • Было ли обсуждение комитетом С++ 11 о том, насколько это необходимо для стандартизации, учитывая, что std::result_of может быть реализовано в терминах decltype довольно легко в любом случае?

4b9b3361

Ответ 1

Наличие функционального типа в качестве параметра позволяет вам иметь неограниченный шаблон "variadic" класса даже в С++ 03. Подумайте об этом: в С++ 03 у нас не было вариационных шаблонов. И вы не можете "перегрузить" шаблон шаблона, как вы можете, с помощью шаблонов функций, - так как же было бы возможно разрешить разные значения "аргументов" функции?

Используя тип функции, вы можете просто добавить частичные специализации числа для различного количества параметров:

template<class Fty>
struct result_of;

template<class F>
struct result_of<F()>{ /*...*/ };

template<class F, class A0>
struct result_of<F(A0)>{ /*...*/ };

template<class F, class A0, class A1>
struct result_of<F(A0, A1)>{ /*...*/ };

// ...

Единственный способ сделать это в С++ 03 - это аргументы шаблона по умолчанию и частично специализированные для каждого случая - недостатком является то, что он больше не выглядит как вызов функции и что любой вид оболочки, использующей result_of внутренне не может просто передать Sig вдоль.


Теперь у вас есть один недостаток в способе-типа: вы также получаете все обычные преобразования, сделанные для "параметров": R(Args...)R(*)(Args...) и, что более важно, T[N]T* и сверху -level cv-квалификаторы отбрасываются (§8.3.5/5):

struct X{
  bool operator()(int (&&arr)[3]);
  long operator()(void*);
};

static_assert(std::is_same<std::result_of<X(int[3])>::type, bool>(), "/cry");

Пример в реальном времени. Выход:

ошибка: статическое утверждение не выполнено:/cry

Другие проблемы связаны с отбрасыванием cv-квалификаторов верхнего уровня:

struct Y{};

struct X{
  bool operator()(Y const&);
  long operator()(Y&&);
};

Y const f();

static_assert(std::is_same<std::result_of<X(Y const)>::type, bool>(), "/cry");

Пример в реальном времени. Выход:

ошибка: статическое утверждение не выполнено:/cry

Ответ 2

Я думаю, что только кто-то понял, что вы можете (ab) использовать нотацию типа функции, чтобы подражать тому, как будет выглядеть соответствующий вызов функтора, и он застрял. Итак, никаких технических причин, просто эстетических.

// the result type of a call to (an object of) type F,
// passing (objects of) types A, B, and C as parameters.
result_of<F(A, B, C)>::type

Ответ 3

result_of был частью TR1, который вышел, прежде чем decltype был добавлен в язык. Но он был разработан с учетом decltype, поэтому изменение реализации result_of на использование decltype прост. Да, это взломать, но он работает.

Ответ 4

(Это расширяет на ответ JohannesD и Джесси Хороший комментарий, но это не подходит в комментарии. Пожалуйста, подтвердите, что другой ответ не этот.)

От N1454 Синтаксис и примеры:

Определение поведения result_of является простым: заданные типы F, T1, T2,..., TN и lvalues ​​F, T1, T2,..., TN этих типов, соответственно, выражение типа

result_of<F(T1, T2, ..., TN)>::type

оценивает тип выражения f(t1, t2, ..., tN).

Это не злоупотребляет системой типов, она красиво изящна!