有没有办法实现自定义类型限定符(类似于const)?我只想允许在具有相同资格的函数内对具有正确资格的函数进行函数调用。
假设我会:
void allowedFunction();
void disallowedFunction();
//Only allowed to call allowed functions.
void foo()
{
allowedFunction();
disallowedFunction(); //Cause compile time error
}
//Is allowed to call any function it wants.
void bar()
{
allowedFunction();
disallowedFunction(); //No error
}
我想这样做的原因是因为我想确保在特定线程上调用的函数仅调用实时安全函数。由于许多应用程序需要硬实时安全线程,因此拥有某种在编译时检测锁的方法将保证我们不会发生许多难以检测的运行时错误。
也许你可以将这些函数放在一个类中,并让允许的函数成为该类的朋友,如下所示:
#include <iostream>
class X
{
static void f(){}
friend void foo(); // f() is only allowed for foo
};
void foo() // allowed
{
X::f();
}
void bar() // disallowed
{
//X::f(); // compile-time error
}
int main()
{
}
您可能可以编写一些疯狂的宏,为您想要允许/禁止的每个功能透明地执行此操作。
扩展 skypjack 的评论:是的,if你可以注释每个 disallowed 函数,这样默认情况下允许未注释的函数。这称为 Passkey 习语。 Godbolt:
// Any object of type TakesLocks serves as a passkey
// for functions that take mutex locks
//
class TakesLocks {
friend int main();
explicit TakesLocks() {} // private constructor
};
void allowedFunction();
void disallowedFunction(TakesLocks);
//Only allowed to call allowed functions.
void foo() {
allowedFunction();
disallowedFunction(TakesLocks()); // error, can't call private ctor
}
//Is allowed to call any function it wants.
void bar(TakesLocks tl) {
allowedFunction();
disallowedFunction(tl); // No error
}
int main() {
foo();
bar(TakesLocks()); // OK, main is a friend of TakesLocks
}
如果您有一个“封闭”的
disallowedFunction
黑名单,这样您就可以枚举它们,并控制它们的签名,这非常有用。但在现实生活中,我们也想要例如需要 TakesLocks
才能调用 printf
和 strftime
等等 — 我们无法强制执行这一点。所以 TakesLocks
基本上是我可以选择的最糟糕的例子。 :)
对于另一种方法,更接近您最初要求的方法,它在学术界取得了巨大成功,但据我所知从未在任何主流编译器中发布,请参阅 Jeffrey Scott Foster 的 Cqual。
编辑:最近我了解到 Clang 通过
enforce_tcb
属性支持相反的方法! “TCB”代表“可信计算基础”,这意味着 TCB 内部的任何内容都绝不能调用 TCB 外部的任何内容。使用-Werror=tcb-enforcement
编译:Godbolt。如果您同意限制对 Clang 的强制执行,并且您同意对每个 allowed 函数进行注释,以便默认情况下不允许使用未注释的函数,请使用此方法。 (这可能限制性太大,因为这意味着例如您不能从带注释的函数调用 puts
或 sin(long double)
或 std::copy
。反之亦然,Clang 悄悄地将一些库函数列入白名单,例如 memcpy
、 sin(double)
和std::move
,进入每个TCB;这可能也有问题,具体取决于您的用例。)
// A function inside the TakesNoLocks TCB must not call
// any function outside that TCB.
//
[[clang::enforce_tcb("TakesNoLocks")]] void allowedFunction();
void disallowedFunction();
//Only allowed to call allowed functions.
[[clang::enforce_tcb("TakesNoLocks")]] void foo() {
allowedFunction();
disallowedFunction(); // error, can't call outside the TCB
}
//Is allowed to call any function it wants.
void bar() {
allowedFunction();
disallowedFunction(); // No error
}
int main() {
foo();
bar(); // OK, main is outside the TCB itself
}