使用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语言扩展)
当在模板中使用CRTP时(或者通常当模板参数作为基类模板参数传递时),是否无法在using声明中命名基础的成员模板?
template< typename d >
struct base {
template< typename >
struct ct {};
template< typename >
void ft() {}
};
template< typename x >
struct derived : base< derived< x > > {
using derived::base::template ct; // doesn't work
using derived::base::ft; // works but can't be used in a template-id
};
Run Code Online (Sandbox Code Playgroud)
在我看来,这是语言中的一个漏洞,因为使用声明语法生成不包含qualified-id.
using-declaration:
using typename(opt) nested-name-specifier unqualified-id ; // have this
using :: unqualified-id ;
unqualified-id:
identifier
operator-function-id
conversion-function-id
literal-operator-id
~ class-name
~ …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
template<typename T>
struct S { static constexpr int bar = T::foo; };
struct U: S<U> { static constexpr int foo = 42; };
int main() { }
Run Code Online (Sandbox Code Playgroud)
GCC v6.1编译它,clang 3.8拒绝它并带有错误:
2:错误:'U'
结构中没有名为'foo'的成员S {static constexpr int bar = T :: foo; };
哪个编译器是对的?
可能是因为我们尝试在其中使用它时U 不是一个完整的类型S吗?
在这种情况下,它应该被认为是GCC的一个错误,但我想知道我是否正好在bug跟踪器上搜索/打开一个问题...
编辑
与此同时,我向GCC 打开了一个错误.
等待它接受答案.
考虑以下类:
template <class Derived>
class BaseCRTP {
private:
friend class LinkedList<Derived>;
Derived *next = nullptr;
public:
static LinkedList<Derived> instances;
BaseCRTP() {
instances.insert(static_cast<Derived *>(this));
}
virtual ~BaseCRTP() {
instances.remove(static_cast<Derived *>(this));
}
};
Run Code Online (Sandbox Code Playgroud)
struct Derived : BaseCRTP<Derived> {
int i;
Derived(int i) : i(i) {}
};
Run Code Online (Sandbox Code Playgroud)
int main() {
Derived d[] = {1, 2, 3, 4};
for (const Derived &el : Derived::instances)
std::cout << el.i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我知道,这是不确定的行为来访问的成员Derived在BaseCRTP<Derived>构造函数(或析构函数),因为Derived构造函数执行后的BaseCRTP<Derived>构造(和析构函数的其他方式)。
我的问题是:在不访问任何成员的 …
我正在研究mixins(用C++编写).我阅读了一些关于mixins的文章,并在C++中发现了两种不同的"近似"mixins模式.
模式1:
template<class Base>
struct Mixin1 : public Base {
};
template<class Base>
struct Mixin2 : public Base {
};
struct MyType {
};
typedef Mixin2<Mixin1<MyType>> MyTypeWithMixins;
Run Code Online (Sandbox Code Playgroud)
模式2 :(可称为CRTP)
template<class T>
struct Mixin1 {
};
template<class T>
struct Mixin2 {
};
struct MyType {
};
struct MyTypeWithMixins :
public MyType,
public Mixin1<MyTypeWithMixins>,
public Mixin2<MyTypeWithMixins> {
};
Run Code Online (Sandbox Code Playgroud)
它们实际上相当吗?我想知道模式之间的实际差异.
我试图了解标准的简单CRTP模式是否有效.
下面的代码编译并按预期工作(在clang上).
但是我对相关标准章节/段落的理解是,虚函数CRTP <Derived,Base> :: DoSomething()的实例化应该在代码的点(B)处,其中Derived的完整声明不是可用.因此内部typedef类型也不应该可用.
任何人都可以指出验证此代码的相关标准章节吗?
换句话说,在这种情况下,虚拟函数被实例化ATFER点C?非常感谢您的任何见解.
弗朗切斯科
//-------------------------
// START CODE
#include <iostream>
struct Type1 {};
struct Type2 {};
struct Base
{
virtual ~Base() {}
virtual void DoSomething() = 0;
};
template< typename T, typename U >
struct CRTP : U
{
virtual void DoSomething() { DoSomething( typename T::Type() ); }
void DoSomething( Type1 ) { std::cout << "1\n"; }
void DoSomething( Type2 ) { std::cout << "2\n"; }
};
// (A) point of inst. of CRTP< Derived, …Run Code Online (Sandbox Code Playgroud) 我正在尝试在microsoft C++编译器14.1(Visual Studio 2017)上编译库,但由于对类方法的模糊调用,我得到一个奇怪的错误.经过一些测试后,我分离了以下代码片段:
#include <iostream>
struct Event
{};
template<typename Derived>
struct State
{
public:
template<typename Fsm>
void onEvent(Fsm& fsm, const Event& event)
{
std::cout << "State::onEvent\n";
}
};
struct DerivedState
: State<DerivedState>
{
public:
using State::onEvent;
template<typename Fsm>
void onEvent(Fsm& fsm, const Event& event)
{
std::cout << "DerivedState::onEvent\n";
}
};
struct Context
{};
int main()
{
DerivedState ds;
Context context;
ds.onEvent(context, Event());
}
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
1> c:\ users\pmas\documents\visual studio
2017\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp(87): error C2668: 'DerivedState::onEvent': ambiguous call to overloaded function
1>c:\users\pmas\documents\visual studio …Run Code Online (Sandbox Code Playgroud) 我正在尝试做这样的事情(在c ++ 11中):
#include <utility>
template <typename T>
struct base {
using type = decltype( std::declval<T>().foo() );
};
struct bar : base<bar> {
int foo() { return 42;}
};
int main() {
bar::type x;
}
Run Code Online (Sandbox Code Playgroud)
失败与
prog.cc: In instantiation of 'struct base<bar>':
prog.cc:8:14: required from here
prog.cc:5:46: error: invalid use of incomplete type 'struct bar'
using type = decltype( std::declval<T>().foo() );
~~~~~~~~~~~~~~~~~~^~~
prog.cc:8:8: note: forward declaration of 'struct bar'
struct bar : base<bar> {
^~~
Run Code Online (Sandbox Code Playgroud)
如何声明bar::fooin 的返回类型的别名base …
我正在尝试将复制和交换习惯用法放入可重用的混音中:
template<typename Derived>
struct copy_and_swap
{
Derived& operator=(Derived copy)
{
Derived* derived = static_cast<Derived*>(this);
derived->swap(copy);
return *derived;
}
};
Run Code Online (Sandbox Code Playgroud)
我打算通过CRTP混合:
struct Foo : copy_and_swap<Foo>
{
Foo()
{
std::cout << "default\n";
}
Foo(const Foo& other)
{
std::cout << "copy\n";
}
void swap(Foo& other)
{
std::cout << "swap\n";
}
};
Run Code Online (Sandbox Code Playgroud)
但是,一个简单的测试显示它不起作用:
Foo x;
Foo y;
x = y;
Run Code Online (Sandbox Code Playgroud)
这仅打印两次"默认",不打印"复制"或"交换".我在这里错过了什么?
我的团队正在开发一个嵌入式系统,我们需要遵循MISRA C++.
我们正在重构代码以使用更少的虚方法,因此我们尝试实现CRTP以使用静态多态而不是动态多态.
但是我们遇到静态多态性需要指针转换的问题,因此我们的静态分析检查器会抱怨.
这是界面
template <typename T>
class UpdateMethod
{
protected:
~UpdateMethod() {}
public:
void operator()() const
{
// [MISRA Rule 5-2-7] violation:
static_cast<const T*>(this)->update();
}
};
Run Code Online (Sandbox Code Playgroud)
以下是其中一个实现:
class A
: public UpdateMethod<A>
{
public:
void update() const {}
};
Run Code Online (Sandbox Code Playgroud)
在通过MISRA检查程序时,它会抱怨static_cast(从ptr转换为ptr(e926).
所以,我的问题是:有没有什么好的方法来实现CRTP而不必压制MISRA警告,所以以安全的方式?
仅有关于指针转换的相关问题: MISRA C++ 2008规则5-2-7违规:指针类型的对象不应直接或间接转换为无关指针类型 我在CRTP中具有相同的错误.
编辑:正如前面提到的只有C++ 03而没有像boost这样的外部库.