简体   繁体   English

条件编译和模板

[英]Conditional compilation and template

Suppose, I have a code: 假设,我有一个代码:

template <typename T>
class C {
public:
    T f() { return m_result; }
    void todo() { m_result = doit<T>(); }
private:
    T m_result;
};

If T is void , I want to return void and have no m_result at all. 如果T void ,我想返回void并且根本没有m_result
But, the compiler does not allow instantiate a void type. 但是,编译器不允许实例化void类型。
One of decision is to create a specialization. 其中一个决定是创建专业化。

template <> class C<void> { /* ... */ }

But I don't what to support the almost identical code. 但我不支持几乎完全相同的代码。
How can I don't instantiate m_result ? 我怎么能不实例化m_result
I can use C++17. 我可以使用C ++ 17。 Thanks! 谢谢!

You could place the data in a base class, then use if constexpr : 您可以将数据放在基类中,然后使用if constexpr

template<class T>
struct C_data{
    T m_result;
    };
template<>
struct C_data<void>{
    };

template<class T>
class C: C_data<T>
  {
  static constexpr auto is_void = std::is_same_v<T,void>;
  public:
  auto f(){
     if constexpr(is_void)
        return this->m_result;
     else
        return;
     }
  void todo(){
     if constexpr(is_void)
       this->m_result = doit<T>();
     else
        doit<T>();
     }
   };

But it can be argued that a the specialization of the class C is cleaner since all member of a template class should depend on all the template parameter (otherwise you should split your class in order to avoid code bloat). 但可以说C类的特化是更清晰的,因为模板类的所有成员都应该依赖于所有的模板参数(否则你应该拆分你的类以避免代码膨胀)。

So I would prefer to fully specialize C, and make part of the class C that are independent of T, a base class of C: 所以我更愿意完全专门化C,并使C语言的一部分独立于T,C的基类:

class C_base{
    //any thing that is independent of T;
    };
template<class T>
class C: public C_base{
    //any thing that depend on T
    };
template<>
class C<void>: public C_base{
    //any thing that depend on T;
    };

You could also specialize member funtion by member function, but I find it less clean. 您还可以通过成员函数专门化成员功能,但我发现它不太干净。

You will find this last code structure in almost all headers of standard library implementations. 您将在标准库实现的几乎所有标题中找到最后一个代码结构。

This works for me: 这对我有用:

#include <type_traits>

template <typename T> T doit() { return T{}; }

template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };

template <typename T>
class C : private result_policy<T> {
  public:
    T f(){
      if constexpr (!std::is_void_v<T>)
        return result_policy<T>::m_result;
    }

    void todo() {
      if constexpr(!std::is_void_v<T>)
        result_policy<T>::m_result = doit<T>();
    }
};

int main() {
  C<int> ci;
  ci.todo();
  int i = ci.f();

  C<void> cv;
  cv.todo();
  cv.f();
}

I used if constexpr from C++17 to work with m_result and stored m_result into policy struct only for non-void types due to partial template specialization. 我使用了来自C ++ 17的if constexpr来处理m_result并且由于部分模板m_result而将m_result存储到仅用于非void类型的策略结构中。

If you can use C++17, then try with if constexpr , std::is_same_v<> and std::conditional_t<> : 如果你可以使用C ++ 17,那么尝试使用if constexprstd::is_same_v<>std::conditional_t<>

#include <type_traits>

// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;

// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;

template <typename T>
class C{
public:
    T f(){ return (T)m_result; } // no problem if T = void

    void todo() {
       if constexpr(!is_void_v<T>)
          m_result = doit<T>();
       else
          doit<T>();
    }
private:
    member_type_t<T> m_result;
};

Actually, as of C++17 there is already a std::is_void_v<> variable template with type_traits . 实际上,从C ++ 17开始,已经有一个带有type_traitsstd::is_void_v<>变量模板。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM