Могут ли несколько единиц перевода иметь объявления одного и того же шаблона с разными аргументами шаблона по умолчанию, но с одинаковым определением? Например, нарушает ли следующий код ODR, если единицы перевода в b.cpp
а также c.cpp
связаны вместе?
// a.hpp
template <bool> class x {...};
// b.cpp
template <bool = true> class x;
#include "a.hpp"// uses of x<>
// c.cpp
template <bool = false> class x;
#include "a.hpp"// uses of x<>
Это зависит. Аргумент по умолчанию не менять По определению шаблона это одно и то же. Но это меняет определение вещей, которые используют шаблон, когда они не дают аргументов.
Рассматривать:
// d.hpp
struct Broken {
x<> member;
};
И использует этот заголовок:
template <bool = true> class x;
#include "d.hpp"// use Broken
template <bool = false> class x;
#include "d.hpp"// Use Broken
Теперь ваша программа нарушает ODR, как видит одна единица перевода Broken
как содержащий x<true>
в то время как другой переводчик видит Broken
как содержащий x<false>
,
Более простым и безопасным подходом было бы объявить константу в ваших .cpp и не изменять шаблон:
// b.cpp
#include "a.hpp" // no default argument
const bool default = true;
// any use of x<> becomes x<default> in the rest of the code
// similarly for c.cpp
Определение шаблона одинаково во всех единицах перевода, и вы получите некоторый эффект, подобный тому, что вы хотите. Обратите внимание, что default
там есть внутренняя связь, так что разные default
объекты не будут вызывать нарушения ODR.
Здесь применяется та же осторожность, что и раньше, если вы замените определение Broken
использовать default
и значение определяется как разное в разных единицах перевода, это все равно будет нарушением правила ODR.
Других решений пока нет …