我有一个关于使用嵌套多态类中友元函数来检索类型信息的问题。
我有以下的代码这表明我在做什么。鉴于两班,A<T>
和B<T>
,我可以创造一个保存了A
或B
运行时多态性包装。在实践中,这种包装可以容纳任何东西,包括具有相似的静态接口另一个模板类。
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';
}
};
该包装来自肖恩家长运行时多态性的概念,但我有一个需要检索一些操作类型的信息。比如,也许我可以添加一个A
和B
,但不是一个A
和C
。基本上,如果我把模板化包装类中的朋友的功能,我可以把对象恢复到原来的类型。
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_cast
友元函数内的Concept
类,因为它的类型可以从Model<T>
类的上下文中推断出来。
所以,我可以用这样的代码:
Wrapper a(1);
B<int> b{2};
someFriend(a, b);
其输出:
Hello from A! 1
Hello from B! 2
3
我的问题是,是否有某种不可预见的问题,做事情这样。另外,如果我替换指针举行的对象,应在static_cast
还能用吗?
一些初步的测试中,我已经运行表明,这是相当可靠的,但我偶尔也会碰到问题,即调用似乎“专业”周围的第一个对象,然后,如果指针变成一个新的对象不切换。
Here是对代码的链接。
您违反ODR(一个定义规则),因此你的代码是形成不良的,没有诊断需要。
特别:
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs);
有这多个定义;其实,还有每一个Model<T>
。通过ODR,必须有这样的一个定义。
伊利诺伊州形成,没有诊断需要(IL-NDR)是你可以在C ++标准的土地最糟糕的事情。
您所看到的现象是一些随机的实现被调用,和“大棒”。什么都没有安全正在发生。