【问题标题】:Decoupling type traits definition from implementation将类型特征定义与实现分离
【发布时间】:2014-01-20 16:38:01
【问题描述】:

让我们考虑以下类,它检查提供的类型是否为字符串,并使用类型特征根据结果调用不同的函数。原始源码对 Obj 有类型依赖,这是一个简化的例子:

template <typename Obj> 
class example {
    public:            
        template <bool IdIsString = std::is_same<std::string, Obj>::value>
        typename std::enable_if<IdIsString, void>::type
        doStuff() {
            this->object->doSomething();
        }

        template <bool IdIsString = std::is_same<std::string, Obj>::value>
        typename std::enable_if<!IdIsString, void>::type
        doStuff()  {
            this->object->doSomethingElse();
        }
     private:
        AnyObject object;
};

如果不在定义中提供每个类型特征案例,我将如何将定义(例如,将其存储在 example_inline.hpp 中)与类解耦?

理想的解决方案如下所示:

// header.hpp
template <typename Obj> 
class example {
    public:
        void doStuff(); 
}

// header_inline.hpp
template <typename Obj>
template <bool IdIsString = std::is_same<std::string, Obj>::value>
typename std::enable_if<IdIsString, void>::type
example::doStuff() {
   // ...
}

// ...

以上显然是不可能的。一种解决方案是将 type_trait 函数与类分离并将其放入详细命名空间中,但这意味着我必须始终将 AnyObject (从这个意义上说,所有由该函数修改的对象)传递给它,这似乎不是很优雅。

这个问题有好的解决方案吗?我真的很希望有问题的标题易于阅读,而不会被大量 enable_if 弄乱。

感谢您对此事的任何意见。

【问题讨论】:

  • 标签调度怎么样?
  • @dyp 不知道那个成语,但这似乎是一个理想的解决方案:) 我会将您的答案标记为接受,以防您想为其他有相同情况的人详细说明问题。
  • 简单的if 怎么样?在您的示例中,似乎不依赖于实际类型,因此两个调用都是有效的,您可以只使用 if(std::is_same&lt;std::string, Obj&gt;::value)..
  • 原源码中有不少类型依赖,我只是把它放在函数体之外。标记调度非常适合我正在使用的代码,再次感谢。

标签: c++ c++11 typetraits


【解决方案1】:

可以根据std::is_same的返回值重载:

template<typename T>
class example
{
private:
    void doStuff(std::true_type)
    {
        obj->doSomething();
    }

    void doStuff(std::false_type)
    {
        obj->doSomethingElse();
    }
public:
    void doStuff()
    {
        doStuff(std::is_same<T, std::string>{});
    }
};

【讨论】:

  • 也称为标签调度 :) 但我未能将我的答案表述为俳句:(
【解决方案2】:

在这种简单的情况下,您还可以将doStuff 专门用于类模板的模板参数:

#include <iostream>
#include <string>

template<class T>
struct example
{ void doStuff(); };

template<class T>
void example<T>::doStuff()
{ std::cout<<"default\n"; }

template<>
void example<std::string>::doStuff()
{ std::cout<<"string\n"; }

int main()
{
    example<int>{}.doStuff();
    example<std::string>{}.doStuff();
}

Live example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-08
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-01
    • 2020-07-03
    • 1970-01-01
    相关资源
    最近更新 更多