使用友元函数从多态类中检索类型信息

Using friend functions to retrieve type information from a polymorphic class?

本文关键字:检索 类型 信息 多态 友元 函数      更新时间:2023-10-16

我有一个关于在嵌套多态类中使用友元函数来检索类型信息的问题。

下面的代码演示了我正在做的事情。给定两个类A<T>B<T>,我可以创建一个包含AB的运行时多态包装器。在实践中,这个包装器可以容纳任何东西,包括另一个具有类似静态接口的模板化类。

template<typename T>
struct A {
T value_;
A(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from A! " << value_ << 'n';
}
};
template<typename T>
struct B {
T value_;
B(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from B! " << value_ << 'n';
}
};

包装器来自SeanPrent的Runtime多态性概念,但我需要检索一些操作的类型信息。例如,也许我可以添加AB,但不能添加AC。基本上,如果我在模板化包装器类中放置一个友元函数,我就可以将对象强制转换回其原始类型。

class Wrapper {
private:
class Concept {
public:
virtual ~Concept() = default;
virtual void sayHello() const = 0;
};
template<typename T>
class Model final
: public Concept {
private:
T data_;
public:
Model(T data) : data_(data) {}
virtual void sayHello() const override {
data_.sayHello();
}
private:
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs) {
T x = static_cast<const Model<T> &>(lhs).data_;
x.sayHello();
rhs.sayHello();
auto y = x.value_ + rhs.value_;
std::cout << y << 'n';
}
};
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs);
std::shared_ptr<const Concept> ptr_;
public:
template<typename T>
explicit inline Wrapper(T a)
: ptr_(std::make_shared<Model<A<T>>>(std::move(a))) {}
template<typename U>
friend inline void someFriend(Wrapper &lhs, B<U> &rhs) {
doSomething(*lhs.ptr_, rhs);
}
};

注意,我能够在友元函数中static_castConcept类,因为它的类型可以从Model<T>类的上下文中推导出来。

所以我可以使用这样的代码:

Wrapper a(1);
B<int> b{2};
someFriend(a, b);

哪个输出:

Hello from A! 1
Hello from B! 2
3

我的问题是,以这种方式做事是否存在某种无法预见的问题。此外,如果我替换指针中的对象,static_cast是否仍然有效?

我运行的一些初步测试表明它相当可靠,但我偶尔会遇到这样的问题,即调用似乎围绕第一个对象"专门化",然后如果指针变为新对象,就不会切换。

这是代码的链接。

您违反了ODR(一个定义规则),因此您的代码格式不正确,不需要诊断。

具体而言:

template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs);

对此有不止一个定义;事实上,每个Model<T>都有一个。ODR对此必须有一个定义。

格式错误,无需诊断(IL-NDR)是C++标准领域中最糟糕的事情。

您看到的症状是调用了一些随机实现,并且"卡住"了。没有发生任何安全的事情。