шаблоны и операторы приведения - PullRequest
4 голосов
/ 20 апреля 2010

Этот код компилируется в CodeGear 2009 и Visual Studio 2010, но не в gcc. Почему?

class Foo
{
public:
    operator int() const;

    template <typename T> T get() const { return this->operator T(); }
};

Foo::operator int() const
{
    return 5;
}

Сообщение об ошибке:

test.cpp: внутри функции-члена `T Foo :: get () const ':
test.cpp: 6: ошибка: в классе const Foo нет члена с именем operator T

Ответы [ 4 ]

9 голосов
/ 20 апреля 2010

Это ошибка в G ++. operator T является неквалифицированным зависимым именем (потому что оно содержит T и поиск, таким образом, будет различным в зависимости от его типа). Как таковой он должен быть найден при создании экземпляра. Стандартные правила

Два имени одинаковы , если

  • ...
  • это имена пользовательских функций преобразования, сформированных с одним и тем же типом.

Таким образом, имя типа, указанное после ключевого слова оператора, никоим образом не должно совпадать с лексическим. Вы можете применить следующий обходной путь, чтобы заставить GCC рассматривать его как зависимое имя

template<typename T, typename>
struct identity { typedef T type; };

class Foo
{
public:
    operator int() const;

    template <typename T> T get() const { 
      return this->identity<Foo, T>::type::operator T(); 
    }
};
4 голосов
/ 20 апреля 2010

Я не уверен, каковы точные правила для имен операторов C ++, но я считаю, что он пытается вызвать operator T() вместо operator int(). Почему бы просто не использовать приведение:

template <typename T> T get() const { return static_cast<T>(*this); }

Я не проверял это, но я верю, что это будет более или менее то же самое. Если нет, то должен быть способ сделать это без прямого вызова operator T(). В конце концов, для этого нужны перегруженные операторы.

2 голосов
/ 20 апреля 2010

Мне немного любопытно использовать этот вариант. Я полагаю, это так, что вы можете сказать:

Foo f;
int x = f.get<int>();

но почему бы не сказать:

Foo f;
int x = static_cast<int>(f);

, который немного длиннее для ввода (хотя можно использовать нотацию C), но не требует прыжков с обручем.

2 голосов
/ 20 апреля 2010

Если я немного изменю код так:

template <typename T> T get() const { return operator T(); }

Я получаю следующее с GCC:

есть нет аргументов для «оператора T», что зависит от параметра шаблона, поэтому объявление оператора T должно быть доступно (если вы используете '-fpermissive', G ++ примет ваше код, но допускает использование необъявленное имя устарело)

Но если бы вы использовали -fpermissive, все это работало бы, только если T = int

С другой стороны, почему бы не сделать:

template <typename T> T get() const { return *this; }

Это своего рода точка оператора преобразования.

...