当前位置: 首页 > 知识库问答 >
问题:

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

全誉
2023-03-14

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

没有用于“Bar”初始化的匹配构造函数

问题似乎是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

共有2个答案

卫嘉泽
2023-03-14

当添加第二个模板参数和默认参数时,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认为原始模板的签名与基类中的签名相同。因此,它认为基类版本是隐藏的。

益思博
2023-03-14

叮当声是正确的。[namespace.udecl]/14:

(emhpasis矿)

当使用声明符将基类中的声明引入派生类时,派生类中的成员函数和成员函数模板会覆盖和/或隐藏基类中具有相同名称、参数类型列表、cv限定和ref限定符(如果有)的成员函数和成员函数模板(而不是冲突)。此类隐藏或覆盖的声明被排除在使用声明符引入的声明集中。

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

 类似资料:
  • 所以,我正在做一个家庭作业,我很难遵循一些指示,我把作业贴在下面: 创建一个由五个类组成的层次结构,加上一个作为变量包含在里面的类: Person有四个字符串变量:姓名,地址,电话,电子邮件 学生是Person的子类,有一个额外的int变量状态,其值为1,2,3或4,代表大一,大二,大三,大四 MyDate有三个int变量,分别为年、月和日 员工是Person的子类,有一个String变量offi

  • 问题内容: 在为期末考试而学习时,我在正在学习的书中遇到了以下陈述。考虑以下代码: 是否必须在类B(super(x))的构造函数中调用类A的构造函数。本书指出这不是强制性的,因为它们具有确切数量和类型的参数。但是,当我在Java编译器中尝试此操作时,会抛出以下错误: 类A中的构造函数A不能应用于给定类型;必需:发现整数:无参数原因:实际和正式参数列表的长度不同 问题答案: 编译器会自动插入开头。

  • 问题内容: 我想知道为什么在Java中不继承构造函数?你知道当你上这样的课时: 稍后当你从继承时Super,java会抱怨没有定义默认的构造函数。解决方案显然是这样的: 这段代码是重复的,而不是干的和无用的(IMHO)…因此再次带来了问题: 为什么Java不支持构造函数继承?不允许这种继承有什么好处? 问题答案: 假设构造函数是继承的…则因为每个类最终都派生自Object,所以每个类最终都将带有无

  • 问题内容: 我想要一个构造函数,其参数会自动被所有子类继承,但是Java不允许我这样做 我不希望有写,等等。每个子类。有没有更聪明的方法来解决这个问题? 解决方案#1。构造一个可以在构造函数之后调用的方法。尽管对我的特定设计而言,这是可行的,但是我希望要求用户在构造函数中指定在编译时经过验证的某些参数(例如,不通过varargs / reflection)。 问题答案: 你不能 如果要在基类中有一

  • 人们有时会对类成员函数或成员变量的作用域问题感到困惑,尤其是,当基类与派生类的同名成员不在同一个作用域内时: struct B { void f(double); }; struct D : B { void f(int); }; B b; b.f(4.5); // OK // 调用的到底是B::f(doube)还是D::f(int)呢? // 实际情况往往会让人感到意外

  • 本文向大家介绍JS继承之借用构造函数继承和组合继承,包括了JS继承之借用构造函数继承和组合继承的使用技巧和注意事项,需要的朋友参考一下 借用构造函数继承  在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术(有时候也叫做伪造对象或经典继承)。这种技术的基本思想相当简单,即在子类型构造函数的内部调用超类型构造函数。