Неявное приведение в шаблонах и приведение компилятора - PullRequest
0 голосов
/ 16 февраля 2011

У меня есть очень простой шаблон оболочки:

template<class T>
struct wrapper {
    inline operator T () {
        return v;
    }

    inline wrapper(T v):v(v) { }

    T v;
};

Попытка использовать его с любым не примитивным типом с (например) оператором сравнения, основанным на определяемом им шаблоне, не выглядит многообещающим:

std::string t = "test";
assert(t == t);

typedef wrapper<std::string> string_wrapper;
assert(string_wrapper(t) == string_wrapper(t));

GCC 4.4.5 жалуется на эту ошибку:

error: no match for ‘operator==’ in ‘wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t))))) == wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t)))))’

Что интересно, GCC выполняет тройное приведение шаблона, а затем не использует operator ==, который был определен для std::string.

Я не думаю, что неявное принуждение невозможно, поскольку, если я изменю std::string на int или double, bool или что-нибудь примитивное, GCC выберет правильный оператор.

Я не хочу определять operator == для структуры оболочки, потому что этот оператор - всего лишь пример, и мне нужно wrapper, чтобы «чувствовать» точно так же, как реальный тип относительно операторов.

Просто в приведении GCC неправильно понимает мой синтаксис, если я создаю оболочку и пытаюсь сравнить ее с собой, GCC снова жалуется (хотя и без тройного преобразования), что не может найти соответствующий оператор ==:

typedef wrapper<std::string> string_wrapper;
string_wrapper tw(t);
assert(tw == tw);

error: no match for ‘operator==’ in ‘tw == tw’

Почему GCC не может найти и / или использовать std::string operator == std::string, когда wrapper предоставляет приведение?

Ответы [ 3 ]

1 голос
/ 16 февраля 2011

Этот оператор T называется «оператор преобразования» или «функция преобразования» вместо приведения. «Преобразования» являются неявными; Кастинг явный.

Компилятор не может найти оператор == для std :: string, потому что правила разрешения перегрузки не допускают этого. Более подробная информация о том, что вы действительно пытаетесь сделать, может помочь найти решение.

0 голосов
/ 21 февраля 2011

Спрашивающий ответил сам с некоторым GCC PR, но который действительно не отвечает на его вопрос.

Причина как @Fred описывает.Уменьшаем его:

template<typename T>
struct A {
  operator T() { return T(); }
};

int main() {
  A<std::string>() == A<std::string>();
}

Что может сделать компилятор?Он может вызвать operator std::string() для обоих операндов и затем выполнить сравнение.Но почему он должен делать этот вызов в первую очередь?Сначала нужно найти operator==, который имеет два параметра типа std::string.Давайте посмотрим, как определяется его оператор

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT,traits,Allocator>& lhs,
                const basic_string<charT,traits,Allocator>& rhs);

Там у нас это есть.Сначала нужно сделать вывод аргумента шаблона, и тот факт, что A не совпадает с const basic_string<>, приведет к тому, что этот operator== будет проигнорирован.Вам повезло, что operator== в любом случае найден с использованием ADL, так что он в первую очередь выполняет вывод аргумента (поскольку std::string является аргументом шаблона вашего типа, он будет рассматривать пространство имен std в ADL и найдет этот оператор).

Таким образом, у нас нет подходящего operator== для вызова, и поэтому GCC в порядке с отклонением вашего кода по причинам, которые @Fred привел в двух словах.В конце концов, попытка заставить класс вести себя как другой тип считается неудачной.

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

Видимо, это ошибка GCC 4.5.Код действителен, в отличие от того, что говорит Фред Нурк.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45383

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...