Учитывая следующие декларации:
struct MyClass { };
typedef int MyClass::*Mp;
На обоих gcc 6.2 и компиляторе Clang я пробовал, result_of<Mp(const MyClass)>::type
доходность int&&
,
Резюме моего вопроса: Зачем int&&
и не либо const int&&
или просто int
?
Больше предыстории: стандарт говорит, что result_of
определяется следующим образом:
тип typedef члена должен называть тип
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
Стандарт также определяет INVOKE для объектов указателя на член следующим образом:
— t1. * F, когда N == 1 и f — указатель на член данных класса T и
is_base_of_v<T, decay_t<decltype(t1)>>
правда;
Обратите внимание, что decay_t
только для проверки, применима ли эта пуля. Насколько я могу судить, применение двух приведенных выше пунктов должно дать:
decltype(declval<const MyClass>().*declval<Mp>())
Который дает const int&&
, Итак, я что-то упустил, или библиотеки компилятора не так?
Изменить, 30 августа 2016 г .:
Спасибо за ответы. Несколько человек предложили альтернативные способы получения правильного результата без использования result_of
, Я должен уточнить, что причина, по которой я одержим правильное определение result_of
является то, что я на самом деле реализую ближайшую разумную реализацию result_of
это работает с компилятором до C ++ 11. Итак, пока я согласен, что я могу использовать decltype
или же result_of<Mp(const MyClass&&)>::type
в C ++ 11 они не делают то, что мне нужно для C ++ 03. Несколько человек дали правильный ответ, который заключается в том, что постоянные аргументы функций не являются частью типа функции. Это проясняет для меня вещи, и я буду реализовывать свой pre-C ++ 11 result_of
так что он также отбрасывает эти квалификаторы.
const
удаляется из параметров функции. Вы можете проверить это используя is_same
,
void(int) == void(const int)
Mp(MyClass) == Mp(const MyClass)
result_of<Mp(MyClass)> == result_of<Mp(const MyClass)>
Я думаю, что это объясняется [8.3.5.5]
:
После составления списка типов параметров любой верхний уровень
cv-квалификаторы, модифицирующие тип параметра, удаляются при формировании
тип функции. Результирующий список преобразованных типов параметров и
наличие или отсутствие многоточия или пакета параметров функции
это список параметров типа функции. [Примечание: это преобразование
не влияет на типы параметров. Например,int(*)(const
а также
int p, decltype(p)*)int(*)(int, const int*)
одинаковые типы.
— конец примечания]
Вы можете обойти это, определив свой собственный result_of
это не (не) использовать типы функций:
template <typename F, typename... ArgTypes>
struct my_result_of
{
using type = decltype(std::invoke(std::declval<F>(), std::declval<ArgTypes>()...));
};
Это определение действительно то, что стандарт должен был использовать.
В result_of_t<Mp(const MyClass)>
вы, кажется, пытаетесь спросить, каков тип результата вызова Mp
с const
значение типа MyClass
, Лучший способ спросить это с result_of
было бы result_of_t<Mp(const MyClass&&)>
но обычно проще просто decltype
и забудь это result_of
когда-либо существовал. Если вы на самом деле намеревались спросить результат с const
тогда это будет result_of_t<Mp(const MyClass&)>
,
Это правда, что на высшем уровне const
Параметры функции не имеют значения в объявлении функции. Когда используешь result_of
поэтому имеет смысл предоставлять типы аргументов в качестве ссылок наconst
типы. Это также делает категорию значения явной, без потери выразительности. Мы можем использовать print_type
Хитрость, чтобы увидеть, что происходит, когда мы делаем это:
template <typename...> struct print_type; // forward declaration
print_type<std::result_of_t<Mp(const MyClass)>,
std::result_of_t<Mp(const MyClass&)>,
std::result_of_t<Mp(const MyClass&&)>,
std::result_of_t<Mp(MyClass)>,
std::result_of_t<Mp(MyClass&)>,
std::result_of_t<Mp(MyClass&&)>>{};
Это печатает:
error: invalid use of incomplete type 'struct print_type<int&&, const int&, const int&&, int&&, int&, int&&>'
Таким образом, мы можем вывести:
std::result_of_t<Mp(const MyClass)> == int&&
std::result_of_t<Mp(const MyClass&)> == const int&
std::result_of_t<Mp(const MyClass&&)> == const int&&
std::result_of_t<Mp(MyClass)> == int&&
std::result_of_t<Mp(MyClass&)> == int&
std::result_of_t<Mp(MyClass&&)> == int&&
Мы это видим result_of_t<Mp(const MyClass)>
, result_of_t<Mp(MyClass)>
, а также result_of_t<Mp(MyClass&&)>
все означают одно и то же. Я был бы удивлен, если бы они этого не сделали.
Обратите внимание, что при использовании declval
Вы также предоставляете типы аргументов в качестве ссылок, как declval
объявляется для возврата ссылки. Кроме того, все параметры для std::invoke
ссылки.