我有一个 CRTP 课程
template <typename T>
class Wrapper
{
// ...
};
Run Code Online (Sandbox Code Playgroud)
旨在导出为
class Type : Wrapper<Type>
{
// ...
};
Run Code Online (Sandbox Code Playgroud)
我想通过对模板参数施加约束来强制执行T
。有一个friend
技巧可以做到这一点,但我认为在概念时代应该有更好的方法。我的第一次尝试是
#include <concepts>
template <typename T>
requires std::derived_from<T, Wrapper<T>>
class Wrapper
{
// ...
};
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为我指的是Wrapper
在声明之前。我发现了一些不完全令人满意的解决方法。我可以将约束添加到构造函数
Wrapper() requires std::derived_from<T, Wrapper<T>>;
Run Code Online (Sandbox Code Playgroud)
但是如果我有更多的构造函数也必须受到约束,这就不方便了。我可以用析构函数来做
~Wrapper() requires std::derived_from<T, Wrapper<T>> = default;
Run Code Online (Sandbox Code Playgroud)
但是声明析构函数只是为了穿上它感觉有点傻requires
。
我想知道是否有更好,更惯用的方法来做到这一点。特别是,虽然这些方法似乎有效(在 gcc 10 上测试过),但一件令人不满意的事情是,如果我Type
从派生Wrapper<OtherType>
,那么只有在我实例化 时才会引发错误Type
。是否有可能在定义点出现错误Type
?
使用CRTP有时我会编写如下代码:
// this was written first
struct Foo : Base<Foo, ...>
{
...
};
// this was copy-pasted from Foo some days later
struct Bar : Base<Foo, ...>
{
...
};
Run Code Online (Sandbox Code Playgroud)
并且很难理解出现了什么问题,直到我在调试器中跟踪代码并看到Bar的成员未被使用Base
.
如何在编译时显示此错误?
(我使用MSVC2010,所以我可以使用一些C++ 0x功能和MSVC语言扩展)
我有一个普通的旧CRPT(请不要因访问限制而分心 - 问题与他们无关):
template<class Derived>
class Base {
void MethodToOverride()
{
// generic stuff here
}
void ProblematicMethod()
{
static_cast<Derived*>(this)->MethodToOverride();
}
};
Run Code Online (Sandbox Code Playgroud)
像往常一样打算像这样使用:
class ConcreteDerived : public Base<ConcreteDerived> {
void MethodToOverride()
{
//custom stuff here, then maybe
Base::MethodToOverride();
}
};
Run Code Online (Sandbox Code Playgroud)
现在static_cast
困扰我了.我需要一个向下投射(不是向上投射),所以我必须使用一个明确的演员.在所有合理的情况下,强制转换都是有效的,因为当前对象确实是派生类.
但是如果我以某种方式改变层次结构并且演员现在变得无效呢?
我可以以某种方式强制执行编译时检查,在这种情况下显式向下转换有效吗?
为了代码重用的目的,我有许多派生自同一个基础的结构,但我不想要任何形式的多态.
struct B {
int field;
void doStuff() {}
bool operator==(const B& b) {
return field == b.field;
}
};
struct D1 : public B {
D1(int field) : B{field} {}
};
struct D2 : public B {
D2(int field) : B{field} {}
};
Run Code Online (Sandbox Code Playgroud)
结构D1
和D2
(以及更类似的结构)派生自B
共享公共字段和方法,因此我不需要在每个派生类中复制这些字段和方法.
结构B
永远不会被实例化; 我只使用D1
和的实例D2
.此外,D1
并且D2
根本不应该彼此互动.从本质上讲,我不希望任何多态行为:D1
并且D2
,出于所有目的,应该充当不相关的结构.
我希望任何D1
与其他D1
s 相比较的平等,以及任何D2
与其他D2
s 相比较的平等.由于D1
并且 …
c++ ×4
crtp ×2
c++-concepts ×1
c++17 ×1
casting ×1
inheritance ×1
siblings ×1
static-cast ×1
upcasting ×1