Visual C ++ 2010, ошибка ссылки на значение? - PullRequest
4 голосов
/ 18 февраля 2011

Это ошибка в Visual C ++ 2010 или правильное поведение?

template<class T>
T f(T const &r)
{
    return r;
}

template<class T>
T f(T &&r)
{
    static_assert(false, "no way"); //< line # 10
    return r;
}

int main()
{
    int y = 4;
    f(y); //< line # 17
}

Я думал, что никогда не следует вызывать функцию f (T &&), но она вызывается с T = int &. Выход:

    main.cpp(10): error C2338: no way
          main.cpp(17) : see reference to function template instantiation 'T f(T)' being compiled
          with
          [
              T=int &
          ]

Обновление 1 Знаете ли вы какой-нибудь компилятор C ++ x0 в качестве справочного материала? Я пробовал Comeau онлайн-тест-драйв, но не смог скомпилировать ссылку на r-значение.

Обновление 2 Обходной путь (с использованием SFINAE):

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_reference.hpp>

template<class T>
T f(T &r)
{
    return r;
}

template<class T>
typename ::boost::disable_if< ::boost::is_reference<T>, T>::type f(T &&r)
{
    static_assert(false, "no way");
    return r;
}

int main()
{
    int y = 4;
    f(y);
    // f(5); // generates "no way" error, as expected.
}

Обновление 3 Некоторые из компиляторов запускают static_assert (false, "no way"), даже если нет экземпляра шаблона функции. Обходной путь (спасибо @Johannes Schaub - litb)

template<class T> struct false_ { static bool const value = false; };
...
static_assert(false_<T>::value, "no way");

или

static_assert(sizeof(T) == sizeof(T), "no way");

Ответы [ 2 ]

5 голосов
/ 18 февраля 2011

Насколько я понимаю (и, возможно, я не совсем прав; спецификация немного сложна), правила вывода типов шаблонов сговариваются против вас.

Компилятор сначала пытается заменить все шаблоны (пока он не выбирает - просто ищет варианты) и получает:

  • T const &r соответствует int lvalue с T = int, создавая f(int const &)
  • T &&r соответствует int lvalue с T = int&, а int & && уменьшается до int&, создавая f(int &) (есть правила, говорящие об этом в спецификация ).

Теперь речь идет о выборе правильной перегрузки, и последняя лучше подходит, поскольку первая отличается в cv-квалификации, а вторая - нет. Это также причина, по которой при удалении const вы получаете неоднозначную ошибку перегрузки & mdash; перегрузки оказываются точно такими же.

Ad Update1 : gcc поддерживает многие функции C ++ 0x . Вы можете получить встроенную сборку Windows от mingw или использовать cygwin .

Ad Update2 : Если вам действительно нужны отдельные перегрузки для rvalue и lvalue, это, кажется, единственный вариант. Но большинство шаблонов делают правильные вещи только с любыми ссылками, возможно, используя std::forward для обеспечения надлежащего разрешения вызываемых ими функций в зависимости от того, получили ли они значение rvalue или lvalue).

3 голосов
/ 26 февраля 2011

Ваше исправление не решает проблему со стрельбой static_assert. static_assert(false, ...) по-прежнему будет запускаться для компиляторов, которые анализируют шаблоны во время определения (большинство делают).

Они увидят, что любое создание экземпляра шаблона функции будет некорректно сформировано, и Стандарт позволит им тогда выдавать ошибку для самого шаблона, и большинство будет делать это.

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

template<class> struct false_ { static bool const value = false; };

template<class T>
T f(T &&r)
{
    static_assert(false_<T>::value, "no way"); //< line # 10
    return r;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...