Применимые части стандарта здесь - §8.5.3 / 5, который охватывает инициализацию ссылок, и §3.10 / 6, в котором говорится, что является r-значением и что является l-значением (не всегда очевидно в C ++).
В этом случае ваше выражение инициализации: «N (1)», поэтому вы явно создаете объект с использованием функциональной нотации. Согласно 3.10 / 6 это выражение является rvalue.
Затем мы должны пройти по правилам в 8.5.3 / 5 по порядку и использовать первое, что применимо. Первая возможность, если выражение представляет lvalue или может быть неявно преобразовано в lvalue. Ваше выражение является rvalue, и для неявного преобразования в lvalue потребуется функция преобразования, которая возвращает ссылку, которой в данном случае, по-видимому, не существует, поэтому она, кажется, не применяется.
Следующее правило гласит, что ссылка должна быть на const T (что здесь имеет место). В этом случае выражение является значением типа класса и совместимо со ссылкой со ссылкой (т. Е. Ссылка относится к тому же классу или базе класса). Это означает, что маркер внизу страницы 151 (179 в C ++ 2003 PDF), похоже, применим. В этом случае компилятору разрешается либо привязывать ссылку непосредственно к объекту, представляющему значение r, либо создавать временную копию значения r и привязывать эту временную копию.
Однако в любом случае стандарт явно требует, чтобы: «Конструктор, который будет использоваться для создания копии, должен вызываться независимо от того, выполняется ли копия на самом деле».
Таким образом, я считаю , что gcc прав, когда выдает сообщение об ошибке, а другие технически ошибочны, чтобы принять код. Я немного упростил ваш код до следующего:
class N {
public:
N(int) {}
private:
N(N const&);
};
void plop(N const& data) { }
int main() {
plop(N(1));
}
Когда вызывается с «--A» (режим строгих ошибок), Comeau выдает следующее сообщение об ошибке:
"plop.cpp", line 12: error: "N::N(const N &)", required for copy that was
eliminated, is inaccessible
plop(N(1));
^
Аналогично, при вызове с "/ Za" (режим "Соответствие ANSI") VC ++ 9 дает:
plop.cpp
plop.cpp(12) : error C2248: 'N::N' : cannot access private member declared in class 'N'
plop.cpp(6) : see declaration of 'N::N'
plop.cpp(2) : see declaration of 'N'
while checking that elided copy-constructor 'N::N(const N &)' is callable
plop.cpp(6) : see declaration of 'N::N'
when converting from 'N' to 'const N &'
Я предполагаю, что большинство других компиляторов делают примерно то же самое. Поскольку они оптимизируют вызов конструктора копирования, они обычно не требуют, чтобы он существовал или был доступен. Когда вы просите их максимально точно соответствовать стандарту, они выдают сообщение об ошибке, поскольку это технически необходимо, даже если они его не используют.