result_of для объекта-члена с cv-квалифицированным аргументом

Учитывая следующие декларации:

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 так что он также отбрасывает эти квалификаторы.

20

Решение

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>()...));
};

Это определение действительно то, что стандарт должен был использовать.

8

Другие решения

В 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 ссылки.

5

По вопросам рекламы [email protected]