c++ - C++ 访问尚未定义的模板参数成员
问题描述
用 c++11 做一些元编程。
我想构建一个 EnumWrapper,它可以用于 switch 语句和映射的关键字,但仍然具有类似对象的属性,如 Java Enumerations。
上课:
#include <string>
#include <vector>
template<typename T, int len>
class Enum
{
private:
typename T::Value value; // invalid use of incomplete Type Planet
public:
Enum() = delete;
constexpr Enum( typename T::Value key ) : value( key ) // invalid use of incomplete Type Planet
{
}
// Allow switch and comparisons.
operator typename T::Value() const // invalid use of incomplete Type Planet
{
return value;
}
T& operator=( const T& other )
{
this->value = other.value;
return *this;
}
inline typename T::Value getValue() // invalid use of incomplete Type Planet
{
return value;
}
explicit operator bool() = delete;
Enum& operator=( const Enum& p )
{
this->value = p.value;
return *this;
}
static inline int length()
{
return len;
}
static std::vector<T> values()
{
std::vector<T> values;
values.reserve( length() );
for ( int i = 0; i < length(); i++ )
{
values.push_back( (typename T::Value)i ); // This is fine for some reason
}
return values;
}
static T getMember( std::string name )
{
for ( T p : values() )
{
if ( p.name() == name )
{
return p;
}
}
}
};
class Planet : Enum<Planet, 3>
{
public:
enum Value
{
MERCURY,
VENUS,
EARTH
}
std::string name()
{
switch(this->getValue())
{
case MERCURY:
return "Mercury";
case EARTH:
return "Mercury";
case VENUS:
return "Mercury";
}
}
};
编译器给出了几个“不完整类型星球的无效使用”消息。
将这些类合并为一个类时,代码会编译并按预期工作。但是可重用性和可维护性并没有通过合并的方法给出。
有人可以帮我解决此错误消息吗?
如果需要或想要更多信息,请告诉我。
编辑: 我的预期用途是这样的:
int main()
{
Planet planet = Planet::EARTH;
Planet invalidPlanet = Planet( (Planet::Value)5 );
// attributes with enum working
std::cout << "My Planet is named " << planet.name() << std::endl;
Planet venus = Planet::VENUS;
std::cout << "Gravity of Venus is " << venus.gravitation() << std::endl;
// Switch working
switch ( planet )
{
case Planet::VENUS:
std::cout << "Venus found." << std::endl;
break;
case Planet::EARTH:
std::cout << "Earth found." << std::endl;
break;
default:
std::cout << "Nothing found." << std::endl;
break;
}
// simple comparison
bool isEarth = planet == Planet::EARTH; // true
bool isVenus = planet == Planet::VENUS; // false
std::cout << "Planet is earth: " << ( isEarth ? "true" : "false" ) << std::endl;
std::cout << "Planet is venus: " << ( isVenus ? "true" : "false" ) << std::endl;
// works in Map
std::map<Planet, std::string> myMap;
myMap[ planet ] = "MyEarth";
std::cout << "chosen planet: " << myMap[ Planet::MERCURY ] << std::endl;
std::cout << "chosen planet: " << myMap[ Planet::EARTH ] << std::endl;
// Map is not bound to object but bound to enum integer
Planet fakeEarth = Planet::EARTH;
std::cout << "chosen planet: " << myMap[ fakeEarth ] << std::endl;
return 1;
}
解决方案
问题是一个类在它的右大括号之前被认为是不完整的,除了它的成员函数的主体。您的Planet
类取决于其Enum
可用的基类的定义。但是,基类依赖于T::Value
成员函数体的外部,因此您有一个场景,类Planet
最终取决于Planet
可用的类的定义。
您可以enum
从Planet
类中分离出您的并将其作为单独的模板参数传递给基类,如下所示:
template<class ENUM, typename T, int len>
class Enum
{
private:
ENUM value;
//...
};
enum Planets
{
MERCURY,
VENUS,
EARTH
};
class Planet : public Enum<Planets, Planet, 3>
{ /*...*/}
现场演示
另一件要担心的是,它Enum::getMember
可能会退出而不返回任何东西。我建议您将其修改为像这样抛出:
static T getMember( std::string name )
{
for ( T p : values() )
{
if ( p.name() == name )
{
return p;
}
}
throw std::invalid_argument("Could not find" + name);
}
其他小事:
- 您不小心使用了
"Mercury"
所有三个枚举值的名称 - 偏爱
enum class
(enum class Planets
) - 更喜欢
static_cast
代替 C 风格的强制转换 (static_cast<ENUM>(i))
) - 您认为枚举值将从零开始并增加 1 的假设是脆弱的
- 手动传递枚举中值的数量的需要很脆弱
- 奇怪的是,一个有效的实例
enum
有一个这样的方法getValue
,它将返回你实际持有的枚举,但也混合了类似的方法values
,length
用于获取有关所持有的枚举类型的信息;这可能会令人困惑 - 希望当我们在 C++ 中获得元类时,这一切都会变得容易得多。
更新的演示
推荐阅读
- python - 如何从盈透证券 API 获取新闻合约详情?
- python - 列表中无序对值的 Python 数据结构
- c++ - C ++中的“没有调用X的匹配函数”错误
- python - Scipy 最小化:ValueError:传递值的形状为 (10, 10),索引暗示 (1, 10)
- python-3.x - 为什么我没有得到大于 2006 的值?
- ruby - 如何使用 VSCode 执行 Ruby 脚本?
- c# - C# - 转义分号和双引号
- apache-kafka - Broker 故障期间 Apache Kafka 的行为
- javascript - 自底向上合并排序 Javascript 实现
- python - 根据 2 列的范围将新行插入到 pandas 数据框中