静态转换到 CRTP 接口

问题描述

我正在构建一个 CRTP 接口并注意到一些未定义的行为。因此,我构建了一些示例代码来缩小问题的范围。

#include <iostream>

template <typename T>
class Base {
public:
    int a() const { return static_cast<T const&>(*this).a_IMPL(); }
    int b() const { return static_cast<T const&>(*this).b_IMPL(); }
    int c() const { return static_cast<T const&>(*this).c_IMPL(); }
};

class A : public Base<A> {
public:
    A(int a,int b,int c) : _a(a),_b(b),_c(c) {}

    int a_IMPL() const { return _a; }
    int b_IMPL() const { return _b; }
    int c_IMPL() const { return _c; }
    
private:
    int _a;
    int _b;
    int _c;
};

template <typename T>
void foo(const T& v) {
    std::cout << "foo()" << std::endl;
    
    std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
    std::cout << "b() = " << static_cast<Base<T>>(v).b() << std::endl;
    std::cout << "c() = " << static_cast<Base<T>>(v).c() << std::endl;
}

int main() {
    A v(10,20,30);
    
    std::cout << "a() = " << v.a() << std::endl;
    std::cout << "b() = " << v.b() << std::endl;
    std::cout << "c() = " << v.c() << std::endl;
    
    foo(v);
    
    return 0;
}

这段代码输出是:

a() = 10
b() = 20
c() = 30
foo()
a() = 134217855
b() = 0
c() = -917692416

似乎在将实现 CRTP“接口”的子类转换为接口本身时存在一些问题。这对我来说没有意义,因为类 A 显然是从 Base 继承的,所以我不应该能够将 A 的实例转换为 Base 吗?

谢谢!

解决方法

在投射到 Base<T> 时复制和切片。

改为转换为 const Base<T>&

std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
std::cout << "b() = " << static_cast<const Base<T>&>(v).b() << std::endl;
std::cout << "c() = " << static_cast<const Base<T>&>(v).c() << std::endl;
,

事实证明我错误地转换为一个值而不是一个引用

std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;

应该变成

std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;