Шаблон признаков типа C++ для добавления ссылки, если не const


У меня есть шаблон класса, который принимает тип T. У него есть метод. Я хочу, чтобы этот метод возвращал тип T, если это const и T&, Если это неconst.

template<typename T>
class C
{
    static typename add_reference_if_non_const<T>::type method();
};

int main()
{
    assert( is_same<result_of<C<int>::method()>::type, int&>::value );
    assert( is_same<result_of<C<const int>::method()>::type, const int>::value );
}

Как я могу это сделать?

2 3

2 ответа:

Вы хотите, чтобы возвращаемый тип C<int const>::method() был int const, но квалификаторы cv верхнего уровня игнорируются в типах возвращаемых функций. В любом случае, поскольку method() возвращает копию T, Вас действительно волнует, что вы возвращаете T const, а не T?

Учитывая это, я думаю, что вы хотите следующее
using add_reference_if_non_const =
    typename std::conditional<std::is_const<T>{},
                              typename std::remove_const<T>::type,
                              typename std::add_lvalue_reference<T>::type
                >::type;
static add_reference_if_non_const method();

Вы можете заменить typename std::remove_const<T>::type на T, Если хотите вернуть T const, Когда T является типом класса.


Следующая проблема связана с result_of что работает с типом аргументы; то, что вы имеете в вопросе, является вызовом функции C::method. Вам нужно использовать

result_of<decltype(&C<int>::method)()>::type
Но поскольку вам все равно нужно использовать decltype, вы можете полностью избавиться от result_of.
decltype(C<int>::method())

Наконец, вам не нужно assert во время выполнения, когда вы можете выполнять проверки во время компиляции с помощью static_assert

static_assert( is_same<decltype(C<int>::method()),       int&>::value, "");
static_assert( is_same<decltype(C<int const>::method()), int>::value,  "" );

Live demo

Как насчет этого:

template <typename T>
struct add_reference_if_non_const
{
    using type = std::conditional<std::is_const<T>::value, T, std::add_lvalue_reference<T>>::type;
};