C++ 可变参数模板移除函数逻辑

标签 c++ templates c++11 variadic-templates

我已经能够使用我的 previous question 中的可变参数模板取得进一步进展.我现在有一个新问题。在此代码示例中:

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

print 函数包含对 m_pValue2 的引用,当 StateMask 包含 Flag2 时有效。

现在,编译器警告它无法找到 m_pValue2。当 StateMask(在编译时已知)不包含 Flag2(当 IsStateValid() 为假时)。

具体错误如下:

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';

我希望这是可能的。在其他模板编程中,我使用 IsStateValid() 编译出与 StateMask 不匹配的代码段。但是,我从未尝试编译掉可能丢失的成员变量。

有没有人有什么想法?

最佳答案

为什么不起作用

无论类型如何,函数模板中的所有分支都将被编译。 IsStateValid(Flag2) 在编译时为 false 并不重要,if 的主体必须是有效代码。由于在那种情况下没有 this->m_pValue2,这是一个硬错误。

你能做些什么来修复它

您需要将每个打印标志函数转发到一个函数模板,该模板将打印值(如果存在)或不执行任何操作(如果不存在)。我们可以使用函数重载来帮助这里,并确保如果没有这个标志,整个函数将不会被实例化。例如:

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
}

此时您需要做的就是添加适当的 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;
};

关于C++ 可变参数模板移除函数逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32659299/

相关文章:

c++ - 在C++中复制动态分配的数组

c++ - 强制编译器只接受编译时参数( float )

c++ - 为什么这个模板示例代码没有编译?

c++ - 当参数是函数参数包时,在部分排序期间推导模板参数

c++ - 多版本资源

c++ - std::list 可以用于简单的无锁队列吗?

c++ - 无锁实现中没有互斥锁的条件变量

c++ - 在 MinGw 和 Clang 之间将 float 转换为 int 不一致

c++ - 模拟基于范围的 for 循环的开始/结束行为

c++ - std::unordered_set 中的非常量 find()