[英]C++ Variadic Template Remove Function Logic
I've been able to progress further with my variadic template from my previous question .我已经能够使用我之前的问题中的可变参数模板进一步取得进展。 I've now got a new question.
我现在有一个新问题。 In this code example:
在此代码示例中:
#include <iostream>
#include <cstddef>
constexpr std::uint32_t Flag0 = 0x0001;
constexpr std::uint32_t Flag1 = 0x0002;
constexpr std::uint32_t Flag2 = 0x0004;
constexpr std::uint32_t FlagAll = 0xFFFF;
template<std::uint32_t...Cs>
struct flags_tag {constexpr flags_tag(){}; };
template<std::uint32_t...Cs>
struct make_flags{ using type=flags_tag<Cs...>; };
template<std::uint32_t...Cs>
using make_flags_t=typename make_flags<Cs...>::type;
template<std::uint32_t value>
class pValue_t
{
template<std::uint32_t StateMask, class flags>
friend class Compound;
};
template<> class pValue_t<Flag0>
{
public:
pValue_t() :
m_pValue0(reinterpret_cast<void*>(0xFFFFFFFF))
{}
protected:
void* m_pValue0;
};
template<> class pValue_t<Flag1>
{
public:
pValue_t() :
m_pValue1(reinterpret_cast<void*>(0xDEADBEEF))
{}
protected:
void* m_pValue1;
};
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
protected:
void* m_pValue2;
};
template<std::uint32_t StateMask, class flags>
class Compound;
template<std::uint32_t StateMask, std::uint32_t...Cs>
class Compound< StateMask, flags_tag<Cs...> >:
public pValue_t<Cs>...
{
public:
void print()
{
if (IsStateValid(Flag0))
{
std::cout << this->m_pValue0 << '\n';
}
if ((StateMask & Flag1) == Flag1)
{
std::cout << this->m_pValue1 << '\n';
}
// *** THIS IS THE PROBLEM STATEMENT ***
if (IsStateValid(Flag2))
{
std::cout << this->m_pValue2 << '\n';
}
}
static bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
uint32_t m_stateMask;
};
using my_type = Compound< Flag0 | Flag1, make_flags_t<Flag0, Flag1>>;
int main() {
my_type test;
test.print();
}
the print
function contains a reference to m_pValue2
, which is valid when the StateMask
contains Flag2
. print
函数包含对m_pValue2
的引用,当StateMask
包含Flag2
时,该引用有效。
Now, the compiler is warning that it cannot find m_pValue2
.现在,编译器警告它找不到
m_pValue2
。 I would like for the compiler to remove the chunk of code that references m_pValue2
when the StateMask
(known at compile time) does not contain Flag2
(when IsStateValid()
is false).当
StateMask
(在编译时已知)不包含Flag2
(当IsStateValid()
为假时)时,我希望编译器删除引用m_pValue2
的代码块。
The exact error is as follows:确切的错误如下:
main.cpp: In instantiation of 'void Compound<StateMask, flags_tag<Cs ...> >::print() [with unsigned int StateMask = 3u; unsigned int ...Cs = {1u, 2u}]':
main.cpp:95:18: required from here
main.cpp:80:27: error: 'class Compound<3u, flags_tag<1u, 2u> >' has no member named 'm_pValue2'
std::cout << this->m_pValue2 << '\n';
I'm hoping this is possible.我希望这是可能的。 In other template programming, I've used
IsStateValid()
to compile out code segments that don't match the StateMask
.在其他模板编程中,我使用
IsStateValid()
编译出与StateMask
不匹配的代码段。 I've never tried to compile away a possibly missing member variable, however.但是,我从未尝试过编译掉可能丢失的成员变量。
Does anyone have any ideas?有没有人有任何想法?
Why it doesn't work为什么它不起作用
All branches in a function template will be compiled regardless of type.无论类型如何,函数模板中的所有分支都将被编译。 It doesn't matter that
IsStateValid(Flag2)
would be false
at compile time, the body of that if
must be valid code.这不要紧,
IsStateValid(Flag2)
是false
,在编译时的身体if
必须是有效的代码。 As there is no this->m_pValue2
in that case, this is a hard error.由于在这种情况下没有
this->m_pValue2
,这是一个硬错误。
What can you do to fix it你能做些什么来修复它
You need to forward each print flag function to a function template that will either print the value (if it exists) or do nothing (if it doesn't).您需要将每个打印标志函数转发到一个函数模板,该模板将打印值(如果存在)或什么都不做(如果不存在)。 We can use function overloading to help here, and ensure that the entire function will not be instantiated if there is no such flag.
我们可以使用函数重载来帮助这里,并确保如果没有这个标志,整个函数不会被实例化。 For example:
例如:
void print()
{
printImpl<Flag0>();
printImpl<Flag1>();
printImpl<Flag2>();
}
template <uint32_t F>
void printImpl() {
printImpl<F>(std::is_base_of<pValue_t<F>, Compound>{});
}
template <uint32_t F>
void printImpl(std::true_type ) {
// we DO have this flag
pValue_t<F>::print();
}
template <uint32_t F>
void printImpl(std::false_type ) {
// we do NOT have this flag
// so do nothing
}
All you need to do at this point is add the appropriate print()
seg:此时您需要做的就是添加适当的
print()
段:
template<> class pValue_t<Flag2>
{
public:
pValue_t() :
m_pValue2(reinterpret_cast<void*>(0xCAFEBABE))
{}
void print() {
std::cout << m_pValue2 << '\n';
}
protected:
void* m_pValue2;
};
I got this to work ( working example ), but it seems very hacky.我让它工作(工作示例),但它似乎很hacky。 It shows that it's possible - hopefully a more experienced person than I can clean it up.
它表明这是可能的 - 希望一个比我更有经验的人可以清理它。
The idea is to make IsStataValid
a constexpr
and separate the code in question out into another function, which has two variants.这个想法是使
IsStataValid
成为constexpr
并将有问题的代码分离到另一个函数中,该函数有两个变体。 The variant that gets instantiated depends on the compile-time flag:实例化的变体取决于编译时标志:
static constexpr bool IsStateValid(std::uint32_t stateMask)
{ return ((StateMask & stateMask) == stateMask); }
template <typename A = void,
typename T = typename std::enable_if<IsStateValid(Flag2), A>::type>
void blub(int x=0) {
std::cout << this->m_pValue2 << '\n';
}
template <typename A = void,
typename T = typename std::enable_if<!IsStateValid(Flag2), A>::type>
void blub(long x=0) {
}
Then instead of the if
statement in print()
you call the helper function:然后调用辅助函数而不是
print()
中的if
语句:
blub();
typename A
is a dummy parameter to make the enable_if
dependent on a template parameter so SFINAE can kick in. The blub
s take a first parameter of a different type so the compiler doesn't complain about it not being able to be overloaded. typename A
是一个虚拟参数,使enable_if
依赖于模板参数,因此 SFINAE 可以启动。 blub
s采用不同类型的第一个参数,因此编译器不会抱怨它无法重载。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.