Входят ли аргументы шаблона по умолчанию в правило с одним определением?
Могут ли несколько единиц перевода иметь объявления одного и того же шаблона с разными аргументами шаблона по умолчанию, но с одинаковым определением? Например, нарушает ли следующий код 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<>
1 ответ
Это зависит. Аргумент по умолчанию не меняет определение шаблона, он тот же. Но это меняет определение вещей, которые используют шаблон, когда они не дают аргументов.
Рассматривать:
// 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.