2

我想写一个有两个模板参数的类,它们都是布尔值。如果它们设置为 true,它们都可以启用不同的额外功能。我想实现这样的事情(这不起作用):

template<bool A, bool B>
class foo {
private:
    int v1;
#if A
    int v2;
#endif

public:
    void f1() {}
#if B
    void f2() {}
#endif
    int f3() {
        #if A
            return v2;
        #else
            return v1;
        #endif
    }
}

我怎样才能在没有任何性能损失的情况下实现这个目标?

4

3 回答 3

3

CRTP、专业化和重构:

template<typename D, bool A>
struct foo_A
{
public:
  D const* self() const {
    static_assert( std::is_base_of<foo_A<D,A>, D>::value, "CRTP failure" );
    return static_cast<D const*>(this);
  }
  D* self() {
    static_assert( std::is_base_of<foo_A<D,A>, D>::value, "CRTP failure" );
    return static_cast<D*>(this);
  }
  void f3() {
    return self()->v2;
  }
};
template<typename D>
struct foo_A<D, true>
{
private:
  int v2;
public:
  D const* self() const {
    static_assert( std::is_base_of<foo_A<D,A>, D>::value, "CRTP failure" );
    return static_cast<D const*>(this);
  }
  D* self() {
    static_assert( std::is_base_of<foo_A<D,A>, D>::value, "CRTP failure" );
    return static_cast<D*>(this);
  }
  void f3() {
    return self()->v1;
  }
};

template<typename D, bool B> struct foo_B {};
template<typename D>
struct foo_B<D,true> {
  void f2() {}
};

template<bool A, bool B>
class foo:
  foo_A<foo<A,B>,A>,
  foo_B<foo<A,B>,B>
{
private:
  int v1;

public:
  void f1() {}
};

CRTP 让您的帮助类可以静态编译时访问您的类的内容,甚至是其他帮助类。

辅助类的专业化以及适当的重构为您提供了不会呈指数增长的良好条件。您甚至可以在派生类中执行一些通用逻辑,并在每个特化中访问这些值。

于 2013-07-19T17:59:22.753 回答
1

您可以通过为每个维度制作一个基本模板来避免组合爆炸。例如,对于您的代码:

namespace detail
{
    template <typename T, bool> struct impl_foo
    {
        int f3()
        {
            return static_cast<T*>(this)->v1;
        }
    };

    template <typename T> struct impl_foo<T, true>
    {
        int v2;

        int f3()
        {
            return v2;
        }
    };

    template <bool> struct impl_bar { };

    template <> struct impl_foo<true>
    {
        void f2();
    };
}

template <bool A, bool B>
struct MyClass : detail::impl_foo<MyClass, A>, detail::impl_foo<B>
{
    int v1;
}

对于impl_foomixin,我们使用循环模板模式从基类访问主类的元素。

于 2013-07-19T18:00:41.820 回答
0

您可以使用模板专业化:

#include <iostream>

template<bool A, bool B>
class foo;

template<bool B>
class foo<true, B> {
    private:
    int v1;
    int v2;

public:
    void f1() {std::cout << "A\n";}

    int f3() {
        return v2;
    }
};

template<bool A>
class foo<A, true> {
private:
    int v1;

public:
    void f1() {std::cout << "B\n";}
    void f2() {}

    int f3() {
        return v1;
    }
};

template<>
class foo<true, true> {
private:
    int v1;
    int v2;

public:
    void f1() {std::cout << "AB\n";}
    void f2() {}

    int f3() {
        return v2;
    }
};

int main() {
    foo<true, false> a;
    foo<false, true> b;
    foo<true, true> ab;

    a.f1();
    b.f1();
    ab.f1();
}

这打印:


甲乙
乙 _

于 2013-07-19T17:49:15.777 回答