我正在开发一个 C++ 项目,其中使用 CRTP 提供有关序列化对象的类型信息。我添加了一个
static constexpr TypeID TYPE_ID
并将其设置为 Derived::TYPE_ID
并开始收到有关 TYPE_ID
不是我的派生类 TestObject
的成员的编译器错误。我创建了此设置的最小版本,运行良好,但我意识到我正在使用 g++ 编译最小版本,并使用 MSVC 编译完整版本。使用 cl.exe 编译最小版本再次出现错误。
这是我的最小代码:
base.h
#ifndef BASE_H
#define BASE_H
#include <string_view>
class IBase {
public:
virtual ~IBase() = default;
};
template<typename Derived>
class Base : public IBase {
public:
static constexpr std::string_view TYPE_ID = Derived::TYPE_ID;
};
#endif
main.cpp
#include <iostream>
#include "base.h"
class Derived : public Base<Derived> {
public:
static constexpr std::string_view TYPE_ID = "Derived";
};
int main() {
std::cout << Base<Derived>::TYPE_ID << std::endl;
}
使用 cl.exe 进行编译会产生以下输出:
Microsoft (R) C/C++ Optimizing Compiler Version 19.38.33141 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
C:\Users\Harry\temp\cpp_testing\CRTP-test-mimimal\base.h(14): error C2039: 'TYPE_ID': is not a member of 'Derived'
.\main.cpp(5): note: see declaration of 'Derived'
C:\Users\Harry\temp\cpp_testing\CRTP-test-mimimal\base.h(14): note: the template instantiation context (the oldest one first) is
.\main.cpp(5): note: see reference to class template instantiation 'Base<Derived>' being compiled
C:\Users\Harry\temp\cpp_testing\CRTP-test-mimimal\base.h(14): error C2065: 'TYPE_ID': undeclared identifier
C:\Users\Harry\temp\cpp_testing\CRTP-test-mimimal\base.h(14): error C2131: expression did not evaluate to a constant
C:\Users\Harry\temp\cpp_testing\CRTP-test-mimimal\base.h(14): note: a non-constant (sub-)expression was encountered
但是当使用 g++ 时,它编译时没有错误并按预期运行。
为什么会发生这种情况?有什么方法可以让它与 MSVC 编译器一起工作吗?
您可以使用静态函数来代替
TYPE_ID
,并通过从基类调用 Derived
实现来使用 CRTP:
#include <string_view>
#include <iostream>
class IBase {
public:
virtual ~IBase() = default;
};
template<typename Derived>
class Base : public IBase {
public:
static constexpr std::string_view TYPE_ID() { return Derived::TYPE_ID(); }
};
class Derived : public Base<Derived> {
public:
static constexpr std::string_view TYPE_ID() { return std::string_view {"Derived"}; }
};
int main() {
std::cout << Base<Derived>::TYPE_ID() << std::endl;
}