构造函数SFINAE和继承在clang中失败

Constructor SFINAE and inheritence fails in clang

本文关键字:clang 失败 继承 SFINAE 构造函数      更新时间:2023-10-16

以下代码在GCC下编译良好,但在clang中失败并出现错误:

没有用于初始化"条形"的匹配构造函数

问题似乎是clang认为Foo的模板构造函数被Bar的模板构造函数隐藏或覆盖。

这是clang中的bug还是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

Clang是正确的。[命名空间.udcl]/14:

(emhpasis矿(

当using声明符将声明从基类带入中的派生类、成员函数和成员函数模板派生类重写和/或隐藏成员函数和成员具有相同名称的函数模板、参数类型列表、,基类中的cv限定符和ref限定符(如果有的话(而不是冲突(。此类隐藏或重写的声明被排除在外来自using声明符引入的声明集。

这意味着,在这种情况下,foo的继承构造函数模板被Bar的构造函数模板隐藏,无法进行查找。请注意,隐藏时只考虑名称、参数类型列表、cv限定符和ref限定符,即使对于模板也是如此。

当添加第二个模板参数和默认参数时,Clang不会继承构造函数模板。另一方面,当函数的参数列表(C++03风格(中使用SFINAE构造时,它没有问题:
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'tor的参数中,而不更改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认为原始模板的签名与基类中的签名相同。因此,它认为基类版本是隐藏的。

相关文章: