【问题标题】:Execute or skip code based on template parameter contents根据模板参数内容执行或跳过代码
【发布时间】:2014-01-16 00:55:19
【问题描述】:

我想为任意类型 T 创建一个容器。但是,如果 T 有一个头类型的成员(我也定义),我想添加一些功能。如果 T 没有该标头成员,则可以跳过添加的功能。

例如,添加的功能可能是根据执行操作的时间添加时间戳。这是我想要的伪代码:

struct my_header {
  timestamp_t time;
  // ... etc ...
}

template <class T>
class my_container {
  public:
    void some_operation(T val) {
        // condition evaluated at compile time
        if T has a member of type my_header {
            val.header.time = get_current_time();
            // ... etc ...
        }

        // other operations, agnostic to T
    }
};

当然,正如我所拥有的,some_operation 还必须找出类 T 中 my_header 实例的名称。可以通过对要使用的附加功能施加以下要求之一来消除此要求(按顺序从最好到最差):

  • T 类中my_header 的实例必须具有名称header
  • my_header的实例是类T中的第一个成员变量
  • 类 T 派生自 my_header,而不是将其包含为成员变量

使用 C++11 就可以了(实际上是预料之中的)。

【问题讨论】:

  • 您可以根据名称为header 的东西进行检查,即my_header,但不能在没有班级告诉您的情况下不知道名称。
  • @Ken 你想检查 T 的类型吗?
  • 这到底是如何工作的?无论您如何检查变量是否存在,代码都不会编译失败(因为val.header.time)。我认为解决方案将涉及专业化。
  • @remyabel Tag dispatch 可以成为你的朋友。
  • 我从另一个答案中发现了这一点,并对其进行了一些更改。试试看:coliru.stacked-crooked.com/a/fb4dfd66f03561bc。 @Xeo,你可能会觉得很熟悉:p

标签: c++ templates c++11


【解决方案1】:

不是最好的解决方案,但我认为它可以工作。从How to detect whether there is a specific member variable in class?盗取代码

#include <iostream>
#include <type_traits>

struct my_header {
  int time;
};

// begin stolen code
template<typename T, typename V = bool>
struct has_header : std::false_type { };

template<typename T>
struct has_header<T, 
    typename std::enable_if<
        !std::is_same<decltype(std::declval<T>().header), void>::value, 
        bool
        >::type
    > : std::true_type { };
// end stolen code

struct foo
{
    my_header header;
};

template<typename, typename = void>
class my_container;

template<typename T>
class my_container<T, typename std::enable_if<has_header<T>::value>::type>
{
public:
    T val;
    void foo()
    {
        std::cout << val.header.time << "\n";
    }
};

template <typename T>
class my_container<T, typename std::enable_if<!has_header<T>::value>::type>
{
public:
    T val;
    void foo()
    {
        std::cout << "other.\n";
    }
};

int main()
{
    my_container<foo> c;
    my_container<int> c2;
    c.foo(); // garbage
    c2.foo(); // other.
}

【讨论】:

  • 我猜你需要通过在some_operation 上使用enable_if 而不是容器类型来完善答案
【解决方案2】:

remyable的解决方案还不错(+1),但可以简化:

#include <iostream>
#include <type_traits>

struct my_header {
  int time = 0;
};

template<typename T>
using has_header = std::is_same< decltype( T::header ), my_header >;

struct foo
{
    my_header header;
};

template<typename T, typename = void>
class my_container
{
public:
    T val;
    void foo()
    {
        std::cout << "other.\n";
    }
};

template<typename T>
class my_container<T, typename std::enable_if<has_header<T>::value>::type>
{
public:
    T val;
    void foo()
    {
        std::cout << "time: " << val.header.time << "\n";
    }
};

int main()
{
    my_container<foo> c;
    my_container<int> c2;
    c.foo(); // time: 0
    c2.foo(); // other.
}

Live example

当然,这个解决方案仍然使用成员变量称为header的要求,因为C++没有可以迭代类型成员的自省。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 2013-02-21
    • 1970-01-01
    • 2019-11-23
    相关资源
    最近更新 更多