Ответ 1
Похоже, что это вызвано параметрами по умолчанию конструкторов mpz_int
(mpz_int
является typedef для конкретного экземпляра boost::multiprecision::number
), которые используемый для SFINAE (например, при использовании конструктора template <class V>
с const V &
, выберите один конструктор, если V
удовлетворяет критериям X и другому конструктору, если V
удовлетворяет критериям Y).
Маленькое воспроизведение:
#include <type_traits>
struct foo {
template<class T>
foo(T , typename std::enable_if<std::is_integral<T>::value>::type * = nullptr) { }
template<class T>
foo(T , typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr) { }
};
struct bar : foo {
using foo::foo;
};
int main() { }
Этот компилируется в clang, но не g++, создавая ту же ошибку. (Стоит отметить, что в то время как clang компилирует воспроизводимый код выше, он фактически не работает, если вы попытаетесь использовать наследуемый конструктор с одним аргументом, который почти одинаково как плохо. Вы можете заставить его работать в clang, однако, явно поставляя второй параметр.)
Мы можем даже пропустить шаблонность для конструкторов foo
, просто используя вместо этого:
struct foo {
foo(double, int = 0) { }
foo(double, double = 0) { }
};
и все равно получить тот же результат - ошибка в g++, ОК в clang.
Теперь возникает вопрос, действительно ли эта конструкция должна быть принята в соответствии со стандартом. К сожалению, нет ясного ответа. §12.9 [class.inhctor]/p1 говорит, что
Использование-объявления (7.3.3), которое неявно именует конструктор объявляет набор наследующих конструкторов. Набор кандидатов наследуемые конструкторы из класса
X
, названного в Использование-декларация состоит из фактических конструкторов и условных конструкторов, которые являются результатом преобразования дефолтных параметров следующим образом:
- все конструкторы без шаблонов
X
и- для каждого конструктора без шаблона
X
, который имеет по крайней мере один параметр с аргументом по умолчанию, набор конструкторов, который приводит к исключению любой спецификации параметра эллипсиса и последовательно исключая параметры с аргументом по умолчанию от конца списка параметров-типа и- все шаблоны конструктора
X
и- для каждого шаблона конструктора
X
, который имеет по крайней мере один параметр с аргументом по умолчанию, набор шаблонов конструктора, который приводит от опускания любой спецификации параметра многоточия и последовательно опуская параметры с аргументом по умолчанию с конца Параметр-типа список.
Проблема заключается в том, что стандарт фактически не указывает, что произойдет, если эта процедура с последовательным опусканием-параметрами с параметрами по умолчанию приводит к двум конструкторам с одинаковой сигнатурой. (Обратите внимание, что с обоими конструкторами шаблонов foo
выше, опускание параметра с аргументом по умолчанию дает подпись template<class T> foo(T);
.) Хотя в абзаце 7 есть примечание, в котором говорится
Если два объявления-объявления объявляют наследующие конструкторы с те же подписи, программа плохо сформирована (9.2, 13.1), поскольку неявно объявленный конструктор, введенный первым использование-объявления не является объявленным пользователем конструктором и, следовательно, не исключает другого объявления конструктора с тем же подписи с помощью последующей декларации использования.
здесь у нас есть только одно использование-объявления, поэтому примечание не применяется, и, хотя дубликаты деклараций действительно запрещены, можно утверждать, что ссылка на набор в параграфе 1 означает, что дубликаты подписей будут просто рассматриваться как один, так что одно использование объявления-объявления не будет вводить дублирующее объявление.
Эта проблема на самом деле является предметом двух отчетов о дефектах по сравнению со стандартом: CWG 1645 и CWG 1941, и неясно, как будут устранены эти отчеты о дефектах. Одна из возможностей, отмеченная в записке 2013 года в выпуске 1645 CWG, заключается в том, чтобы удалить такие унаследованные конструкторы (которые исходили от нескольких базовых конструкторов), чтобы они вызывают ошибку только при ее использовании. Альтернативный подход, предложенный в проблеме CWG 1941, состоит в том, чтобы заставить наследующие конструкторы вести себя как другие функции базового класса, введенные в производный класс.