使用 CRTP 确定性地生成代码
Using CRTP To Deterministically Generate Code
我最近开始接触模板魔法,尤其是 CRTP。我知道模板是用来让编译器为我们生成代码的,所以我想知道是否可以制作一个模板 "decide" 我们希望它为特定 class 包含函数的哪些部分.例如,如果我有以下代码:
crtp.h
#include <iostream>
using std::endl;
using std::cout;
template<class T>
class A {
public:
void func() {
constexpr unsigned short mask = T::GetMask();
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
}
};
class B : public A<B> {
friend class A<B>;
protected:
static constexpr unsigned short GetMask() { return 0x0001; }
};
class C : public A<C> {
friend class A<C>;
protected:
static constexpr unsigned short GetMask() { return 0x0009; }
};
main.cpp
#include "ctrp.h"
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
using std::getchar;
using std::endl;
int main() {
B b;
C c;
cout << "B:" << endl;
b.func();
cout << endl << "C:" << endl;
c.func();
getchar();
}
执行时产生:
B:
Mask 1
C:
Mask 1
Mask 2
效果很好,完全符合我的要求。从我的角度来看,问题是 if 语句应该是不必要的。当我处理常量表达式时,编译器应该拥有它需要的一切,可以简单地跳过分支并知道执行 class B 的第一部分和 class C.
的两个部分。
我想从中获利,并特别告诉编译器删除特定 class 不需要的部分,以避免在运行时出现不必要的分支。不幸的是,我不知道该怎么做,有什么想法吗?提前致谢
编辑
为了回应一些很棒的建议,C++17 的 constexpr if 表达式是一个近乎完美的解决方案,我不知道它存在,但不幸的是我无法使用。我仅限于使用 C++14。
在编译时使用模板元编程模拟if/else 不能那样工作。您必须想象 if/else 使用不同的思维方式。
而不是
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
您必须使用以下内容:
function1_selector<mask & 1>::dostuff();
function2_selector<mask & 1 << 3 >::dostuff();
哪里
template <bool> struct function1_selector
{
static void dostuff() { /* Do nothing */ }
};
template <> struct function1_selector<true> // Specialize for true
{
static void dostuff() { /* Do something useful */ }
};
类似地为 function2_selector
添加代码。
如果您关心性能,编译器很可能会优化所有 "dead" 分支甚至 if
条件,如果它可以在编译期间对其进行评估的话。
更糟糕的是,在 C++17 constexpr if
之前,所有分支都需要格式正确。在这种情况下,您可以 "outsource" 特殊(静态成员)函数的功能并使用专门化来调用正确的函数。有关示例,请参见@R Sahu 的回答。
我最近开始接触模板魔法,尤其是 CRTP。我知道模板是用来让编译器为我们生成代码的,所以我想知道是否可以制作一个模板 "decide" 我们希望它为特定 class 包含函数的哪些部分.例如,如果我有以下代码:
crtp.h
#include <iostream>
using std::endl;
using std::cout;
template<class T>
class A {
public:
void func() {
constexpr unsigned short mask = T::GetMask();
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
}
};
class B : public A<B> {
friend class A<B>;
protected:
static constexpr unsigned short GetMask() { return 0x0001; }
};
class C : public A<C> {
friend class A<C>;
protected:
static constexpr unsigned short GetMask() { return 0x0009; }
};
main.cpp
#include "ctrp.h"
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
using std::getchar;
using std::endl;
int main() {
B b;
C c;
cout << "B:" << endl;
b.func();
cout << endl << "C:" << endl;
c.func();
getchar();
}
执行时产生:
B:
Mask 1
C:
Mask 1
Mask 2
效果很好,完全符合我的要求。从我的角度来看,问题是 if 语句应该是不必要的。当我处理常量表达式时,编译器应该拥有它需要的一切,可以简单地跳过分支并知道执行 class B 的第一部分和 class C.
的两个部分。我想从中获利,并特别告诉编译器删除特定 class 不需要的部分,以避免在运行时出现不必要的分支。不幸的是,我不知道该怎么做,有什么想法吗?提前致谢
编辑
为了回应一些很棒的建议,C++17 的 constexpr if 表达式是一个近乎完美的解决方案,我不知道它存在,但不幸的是我无法使用。我仅限于使用 C++14。
在编译时使用模板元编程模拟if/else 不能那样工作。您必须想象 if/else 使用不同的思维方式。
而不是
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
您必须使用以下内容:
function1_selector<mask & 1>::dostuff();
function2_selector<mask & 1 << 3 >::dostuff();
哪里
template <bool> struct function1_selector
{
static void dostuff() { /* Do nothing */ }
};
template <> struct function1_selector<true> // Specialize for true
{
static void dostuff() { /* Do something useful */ }
};
类似地为 function2_selector
添加代码。
如果您关心性能,编译器很可能会优化所有 "dead" 分支甚至 if
条件,如果它可以在编译期间对其进行评估的话。
更糟糕的是,在 C++17 constexpr if
之前,所有分支都需要格式正确。在这种情况下,您可以 "outsource" 特殊(静态成员)函数的功能并使用专门化来调用正确的函数。有关示例,请参见@R Sahu 的回答。