Согласно «Правилу одного определения» переменная должна иметь ровно одно определение, если используется odr-used . Это определяется стандартом C ++ 11:
3.2 / 2 Переменная или не перегруженная функция, имя которой появляется в качестве потенциально оцениваемого выражения, используется odr, если только она не является объектом, удовлетворяющим требованиям для появления в константном выражении, а преобразование lvalue-to-rvalue равно немедленно применяется.
и само ODR:
3.2 / 3 Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе в виде odr; Диагностика не требуется.
Как аргументы вызова функции, они не odr-used : они являются константами со значением, указанным в их объявлении, и поэтому могут появляться в константном выражении; и они передаются по значению, и поэтому немедленно преобразуются в значения.
Это не тот случай, когда они используются в условном выражении. Поскольку оба являются lvalue, относящимися к одному и тому же типу, результатом условного выражения будет lvalue, согласно одному из довольно сложных правил, определяющих условный оператор:
5.16 / 4 Если второй и третий операнды являются значениями одной и той же категории значений и имеют один и тот же тип, результат будет иметь тип и категорию значений.
(Это правило допускает выражения типа (a?b:c)=d
.)
Таким образом, сами константы не сразу преобразуются в значения r, и условное выражение не может появляться в постоянном выражении из-за условия времени выполнения; следовательно, они используются odr, и поэтому нуждаются в определении.
Как вы заметили, изменение условия на константное выражение исправляет ошибку связи; так изменил бы тип одной константы. Но выражение в его нынешнем виде требует, чтобы они имели определение в одной (и только одной) единице перевода:
const int MyClass::MinValue;
const int MyClass::MaxValue;