Конструктор SFINAE и наследование терпят неудачу в лязге - PullRequest
2 голосов
/ 05 ноября 2019

Следующий код прекрасно компилируется в GCC, но завершается с ошибкой в ​​clang с ошибкой:

нет подходящего конструктора для инициализации 'Bar'

Кажется, проблема вэтот clang считает, что конструктор шаблона Foo скрыт или перезаписан конструктором шаблона Bar .

Это ошибка в clang или нестандартизированная функция в GCC?

Как решить эту проблему? Я не могу изменить Foo, так как это третье лицо.

#include <type_traits>

struct Foo {
    Foo() = default;

    template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>>* = nullptr>
    Foo(T& object) {}
};

struct Bar : public Foo {

    using Foo::Foo;

    template<typename T, std::enable_if_t<!std::is_trivially_copyable_v<T>>* = nullptr>
    Bar(T& object) {}
};

int main() {
    int i;
    Bar s{i};
}

https://gcc.godbolt.org/z/etvpvF

Ответы [ 2 ]

2 голосов
/ 05 ноября 2019

Clang правильно. [namespace.udecl] / 14 :

(emhpasis mine)

Когда объявление-использование переносит объявления из базового класса в производный класс, членфункции и шаблоны функций-членов в производном классе переопределяют и / или скрывают функции-члены и шаблоны функций-членов с одинаковыми именами, списком типов параметров, cv-qualification и ref-qualifier (если есть) в базовом классе(а не противоречивый) . Такие скрытые или переопределенные объявления исключаются из набора объявлений, введенных с помощью объявления-использования.

Это означает, что в этом случае шаблон конструктора-наследника из foo скрыт от поиска конструктором. шаблон от Bar. Обратите внимание, что только имя, список параметров типа, cv-qualification и ref-qualifier считаются скрытыми даже для шаблонов.

0 голосов
/ 05 ноября 2019

Clang не наследует шаблон конструктора при добавлении второго параметра шаблона и аргумента по умолчанию. С другой стороны, у него нет проблем, когда в списке параметров функции используется конструкция SFINAE (стиль C ++ 03):

struct Foo {
    Foo() = default;

    template<typename T>
    Foo(T& object, std::enable_if_t<std::is_trivially_copyable_v<T>>* = nullptr) {}
};

struct Bar : public Foo {
    using Foo::Foo;

    template<typename T>
    Bar(T& object, std::enable_if_t<!std::is_trivially_copyable_v<T>>* = nullptr) {}
};

Живой пример

В этой версии шаблон конструктора наследуется очень хорошо и используется в разрешении перегрузки, как и следовало ожидать.


Перемещение вашей собственной проверки SFINAE в параметр c'or без изменения Foo также, кажется, разрешает это:

struct Foo {
    Foo() = default;

    template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>>* = nullptr>
    Foo(T& object) {}
};

struct Bar : public Foo {
    using Foo::Foo;

    template<typename T>
    Bar(T& object, std::enable_if_t<!std::is_trivially_copyable_v<T>>* = nullptr) {}
};

Живой пример

Clang считает подпись вашего исходного шаблона идентичной подписи из базового класса. И поэтому он считает версию базового класса скрытой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...