您可能知道 typedef 更像是 C++ 中的别名而不是新类型,详细信息可以在这里看到:http:
//dlang.org/cpptod.html#typedefs
我真的不喜欢链接中提出的解决方案,所以我想知道有没有更好的办法 ?
5 回答
只有一种方法可以在 C++ 中引入新类型 - 使用类关键字 ( /// ... union
) 。有一些方法可以将这些东西隐藏在宏后面,并使这些新类型与旧类型一样直观可用(请参阅 参考资料),但事实仍然是它是引入这种新类型的唯一方法。struct
class
enum
BOOST_STRONG_TYPEDEF
想象一下,你有一个newtype
关键字可以创建一个强 typedef:
newtype foo = int; // with 'using' alias syntax
与该类型之间的转换将如何工作?如果没有转换,您永远无法为新类型的对象分配任何值。只有显式转换可能看起来很直观,但是如果您真的想要隐式转换并且仍然能够重载怎么办?好吧,运气不好。您也许可以添加各种语法以将决定权留给用户,但我相信您总是可以提出需要新语法的极端情况。只需将其设为 a struct
,将其隐藏在宏后面并完成即可。
通用“没有时间制作适当的界面”宏:
#define STRONG_CLASS_TYPEDEF(oldType, newType) \
struct newType : private oldType { \
template<typename... T> \
newType(T... foo) : oldType(foo...) {} \
oldType* operator->() { return this; } \
oldType& operator*() {return *this;} \
};
如果您的编译器不支持可变参数模板,则需要手动插入所需的任何构造函数。这基本上是一个自己构建的继承构造函数。
不幸的是,我认为不可能将新类型隐式转换为基类,而是公开其所有公共字段。有一些解决方法:
您可以只using oldType::X;
使用您需要的所有方法和变量。这绝对是最好的解决方案,但需要一段时间才能完成。
或者使用偷偷摸摸的箭头运算符重载和调用foo->method();
。或者将新的强类型“取消引用”到基本类型中。这些基本上只是一个花哨的显式演员表。但是考虑operator oldType()
(显式与否)甚至不适用于私有继承......
无论如何,这里有一个强类型的std::string
andName
例子。
struct Name : private std::string {
template<typename... T>
Name(T... foo) : std::string(foo...) {}
std::string* operator->() { return this; }
const std::string& operator*() {return *this;}
//The above is obviously a bad idea if you want to use this alongside pointers
using std::string::resize;
using std::string::size;
using std::string::insert;
using std::string::operator[];
// etc.
//Simplest to use, but a bit more to set up
};
此外,您必须包装非成员运算符重载(==
本例中为 std::string)。
bool operator==(Name& lhs, Name& rhs) { return *lhs == *rhs; }
//Note: "Dereference" turns it into a std::string, as above
公平的警告,除了基本的力学之外,我没有测试太多。它可能会增加(非常)少量的开销。但是实际上空的类可能被优化掉了。
用于BOOST_STRONG_TYPEDEF
在 C++ 中创建“strongdefs”。没有内置的语言功能可以这样做。
也就是说,了解您要解决的真正问题会很有趣,因为我发现在typedef
我处理的代码中对非别名的需求非常少。
C++ 中的新类型只能通过某种方式聚合子类型来产生。但是由于函数重载是基于静态类型的,所以所有的操作和函数都必须重新声明。
C++typedef
就像 D 一样alias
。
如果起始类型是类或结构,继承会有所帮助(至少操作仍然可以像使用旧参数一样工作)但一切都与返回类型有关,并且必须正确重新定义转换,否则一切都会无差别地上下转换,从而消失新类型的优势。
C++ 中有很多方法可以执行类型检查。考虑以下代码,基本思想与链接中给出的示例相同,但我认为它更简单:
struct Handle2 {void * ptr;} ;
void bar(Handle2) {}
void foo(void *) {}
int main() {
Handle2 h2 = {(void*)-1};
foo(h2); //! won't pass through compiling
bar(h2);
}