Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何仅在成员函数中使用静态断言?_C++_Inheritance_Static Assert - Fatal编程技术网

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();