ADL не может найти оператора потока с соответствующими квалификаторами для определенного пользователем типа

Я компилирую службу x64 в Microsoft Windows 7 с Visual Studio 2010, используя Увеличить вариант примерно так:

namespace my_ns
{
    typedef struct {} empty_t;
    typedef std::pair<size_t, std::shared_ptr<char>> string_t;
    typedef boost::variant<empty_t, double, long, string_t> variant_t;
    typedef std::map<unsigned short, variant_t> variant_map_t;
}

В тот день, когда я избавлюсь от этого string_t и заменю его на std::string, я куплю своему боссу и команде пончики. Но мы здесь не поэтому...

Вариант Boost поддерживает операторы потока для содержащихся в нем типов при условии, что тип имеет перегрузку. Так что я:

namespace my_ns
{
    std::ostream &operator<<(std::ostream &, const empty_t &);
    std::ostream &operator<<(std::ostream &, const string_t &);
}

И все же меня мучает сообщение об ошибке:

error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const T3' (or there is no acceptable conversion)

T3 относится к string_t.

Нарушающий код, генерирующий ошибку, существует в следующем контексте. Это подробно, поэтому вы, читатель, имеете соответствующую контекстную информацию:

namespace my_ns
{
    void Widget::public_method(std::ostringstream &os) const
    {
        //variant_map_t Widget::the_map; // Private Widget member.

        // This here is a C++11 lambda in a standard loop algorithm, if you didn't recognize the syntax.
        std::for_each(the_map.begin(), the_map.end() [&os](variant_map_t::value_type value)
        {
            os << value.first << '=' << value.second << ' ';
        });
    }
}

Я попытался удалить правые квалификаторы и ссылку, думая, что передача копии по значению сбьет квалификаторы (вероятно, не так блестяще в свете общего указателя), и я попытался переместить объявления из пространства имен в глобальную область, надеясь, что ADL подхватит это по какой-то причине (концептуально я получаю ADL, но для меня все еще есть немного черной магии).

Я не знаю, что еще делать. Какова природа этой ошибки, помимо того, что компилятор не может найти оператор вставки с константой, квалифицированной rhs? Как это может быть, когда это прямо там? И какое разрешение?


person Matthew Reddington    schedule 14.05.2012    source источник
comment
Можете ли вы опубликовать SSCCE? Как есть, мне трудно поверить, что код, который вы показали, вызывает показанную вами ошибку.   -  person ildjarn    schedule 15.05.2012


Ответы (1)


Не помогает то, что вы добавляете typedef в свое пространство имен, std::pair и std::ostream по-прежнему являются частью пространства имен std. Так что компилятор будет искать оператор << там, а не в вашем пространстве имён.

person Bo Persson    schedule 14.05.2012
comment
Это правильно? Расширение пространства имен std? Каждая фибра моего тела говорит, что должно быть лучшее решение. Я бы предпочел не расширять пространство имен, которое не принадлежит мне. Но пока, с недоверием и... немного желчи в горле, я буду терпеть. - person Matthew Reddington; 15.05.2012
comment
Нет, я не говорил, что вы должны добавлять операторы в пространство имен std — это не разрешено. Я сказал, что добавление их в пространство имен your не работает, потому что они там не найдены. :-) Это ловушка-22, нарушать правила или не работать? Твой выбор! - person Bo Persson; 15.05.2012
comment
Ну, это отстой. Невозможно перегрузить операторы потока или стандартные типы. В конце концов мне повезло с несколькими поисками по ключевым словам, и лучшее, что у кого-либо есть, — это написание функторов или лямбда-выражений для каждого случая. - person Matthew Reddington; 15.05.2012