C++ 如何仅在成员函数中使用静态断言?
我有以下计划:C++ 如何仅在成员函数中使用静态断言?,c++,inheritance,static-assert,C++,Inheritance,Static Assert,我有以下计划: struct Baz {}; struct Qux {}; struct Base { virtual ~Base() {} virtual void foo() = 0; }; template<typename T> struct Identity { static bool const value = false; }; template<typename T> void bar(T) { static_assert(Identity&l
struct Baz {};
struct Qux {};
struct Base {
virtual ~Base() {}
virtual void foo() = 0;
};
template<typename T> struct Identity { static bool const value = false; };
template<typename T> void bar(T) { static_assert(Identity<T>::value, "Busted!!!"); }
template<> void bar<Baz>(Baz) {}
template<typename T>
struct Derived : Base {
T m;
void foo() { bar(m); }
};
int main() {
Base *b0 = new Derived<Baz>;
b0->foo();
Base *b1 = new Derived<Qux>;
(void) b1;
}
但当稍后在代码中程序员尝试调用:
b1->foo(); // compile error static assert
《标准》说了一件有趣的事情: 实现不应隐式实例化函数 模板、变量模板、成员模板、非虚拟成员 函数、成员类、类模板的静态数据成员,或 constexpr if语句的子语句,除非是这样的实例化 是必需的。未指定是否为一个实现 隐式实例化类模板的虚拟成员函数 如果虚拟成员函数不会被实例化 实例化一个虚拟函数的决定取决于实现,但只有在其他情况下不需要的情况下。因此,我们面临的问题是:根据标准本身,何时需要定义 答案如下: 在类中声明的虚函数应定义,或在该类中声明为纯函数,或两者都定义;不需要诊断 类模板专门化的隐式实例化导致声明的隐式实例化,而不是类成员函数的定义、默认参数或noexcept说明符的隐式实例化 因此,类模板的任何实例化都将实例化
Derived::foo
的声明,通过连锁反应,它需要一个定义。因此,如果定义可用,那么它也必须实例化
实现可以利用第一段中引用的回旋余地的唯一方法是,如果Derived::foo
也是纯虚拟的。举个例子,两者都可以,并且都可以这样做。当然,这对你的帮助可能有限
因此,长话短说,只要函数是虚拟的(而不是纯虚拟的),它就不是初学者。@StoryTeller给出了一个参考规范的详细答案,等等。但我将推回你的问题,问你真正想做什么。在编写问题时,答案显然是“否”,因为您要求的是编译时错误,该错误只能在运行时确定。例如:
Base *b;
if (user_input() == 42) {
b = new Derived<Baz>();
} else {
b = new Derived<Qux>();
}
b->foo();
如果foo
是一个非虚拟模板化方法,它可能会在编译时验证基类型,然后分派给虚拟方法。(可能需要更改foo的签名才能以某种方式获得该类型。)
更好的解决方案是将接口中不同类型的功能分解为不同的类,并引入一种机制来获取给定具体类上的特定接口。如果您手头有Concrete types类,则可以在编译时检查此问题,如果执行接口的动态查找,则可以在运行时检查此问题。我认为这是不可能的,因为即使未调用
foo
,它也将用于填充vtable。我认为不会。在派生的
的实例化过程中,foo
将被完全编译。而且编译器不能总是知道是否会调用某些重写。虚拟函数隐式使用odr。只要foo
是虚拟的,模板就会被实例化。@StoryTeller这是可以理解的,我正在寻找一个可能愚弄编译器/语言的技巧。如果你也能得到rose,我会喜欢它的,正如你所知:)我可以通过使用静态断言来实现我在运行时想要的。事实上,这就是我现在正在做的。继续…当然,但询问如何在运行时而不是编译时进行检查总是好的。通常可以更改接口以允许这样做。考虑一下我的答案,鼓励你思考一下,如果是在你的情况下。我有一个API用户专门处理某些功能模板的方案(例如,代码>模板空格栏(BAZ)< /COD>专门代码>模板空格栏(T)< /代码>)。目标是定义不同的派生的类的行为,然后利用它们的公共基类在公共基础上对它们进行操作,并将它们统一处理。用户只能为其类型支持/具有意义的函数指定专门化。但是,如果偶然使用了一个她没有提供专门化的函数,编译器将以一条信息性错误消息中断编译…现在我使用运行时断言,但是这样,如果程序调用该函数,用户将得到一个错误。也就是说,如果错误不在应用测试用例的分支中,那么程序根本不会中断,因此可能会中断给客户。在编译时中断比较好,因为它在任何情况下都会提醒用户她犯了错误。
Base *b;
if (user_input() == 42) {
b = new Derived<Baz>();
} else {
b = new Derived<Qux>();
}
b->foo();
Derived<Qux> d = new Derived<Qux>();
d->foo();