c++0x: сопоставление ссылочного параметра Rvalue для классов с неявными конструкторами const char *

У меня есть класс с неявным конструктором const char *. Моя интуиция подсказывает мне, что не должно иметь значения, явно или неявно я вызываю конструктор, но, по-видимому, это имеет значение в случае const char *, и я не понимаю, почему. Компилятор VC++ сопоставляет foo(const String &t) для первого вызова foo в приведенном ниже коде:

struct Str
{
    Str(const char *c)
    {
        value = c[0];
    }
    Str(double c)
    {
        value = char(c);
    }
    char value;
};

void foo(const Str &t)
{
    cout << "const Str &t matched\n";
}

void foo(const Str &&t)
{
    cout << "const Str &&t matched\n";
}

void main()
{
    foo("v");
    foo(Str("v"));
    foo(5.0);
    foo(Str(5.0));
}

Во всем остальном он соответствует версии foo для Str &&t. Почему он ведет себя по-другому в неявном случае «v»? И что я должен изменить, чтобы версия && foo соответствовала? (представьте, что foo — это, например, функция vector::push_back — мне бы не хотелось явно приводить все мои строковые литералы.)


person Matt Fisher    schedule 15.05.2011    source источник


Ответы (1)


Это известная проблема со спецификацией ссылок rvalue, которая теперь исправлена, но не была обнаружена, когда MSVC10 реализовал их. По сути, при принятии решения о привязке к ссылкам lvalue или rvalue учитывается исходное значение lvalue или rvalue аргумента, а не после того, как могут произойти какие-либо преобразования, если они потребуются. Это связано с тем, что исходные ссылки на rvalue были слишком жадными в отношении привязки к lvalue, и была введена некоторая строгая формулировка для обеспечения безопасности ссылок на rvalue, но оказалось, что это было немного чрезмерно усердно. Вам не нужен пользовательский тип, чтобы продемонстрировать это — простой std::string подойдет.

person Puppy    schedule 15.05.2011
comment
Мне даже не пришлось проверять поведение STL в этом случае, потому что я предполагал, что он будет работать правильно с std::string (поскольку неявное преобразование строковых литералов в std::string чрезвычайно распространено). - person Matt Fisher; 16.05.2011
comment
@Matt Fisher: Это ошибка в самом стандарте (в том виде, в каком он существовал тогда), а не в какой-либо библиотеке или отдельном компиляторе, и это было изменение в последнюю минуту, чтобы исправить гораздо более серьезный класс ошибок. Для них вполне разумно не исправить эту относительно незначительную деталь. - person Puppy; 16.05.2011