【问题标题】:const-ness as template argumentconst-ness 作为模板参数
【发布时间】:2011-04-10 19:54:58
【问题描述】:

我有两个结构:

  // ----- non-const -----
  struct arg_adapter
  {
      EArgType type;  // fmtA, fmtB, ...

      union
      {
        TypeA * valueA;
        TypeB * valueB;
        // ... more types
      }

      arg_adapter(TypeA & value) : type(fmtA), valueA(&value) {}
      arg_adapter(TypeB & value) : type(fmtB), valueB(&value) {}
      // ...
  }

  // ----- const version -----
  struct const_arg_adapter
  {
      EArgType type;  // fmtA, fmtB, ...

      union
      {
        TypeA const * valueA;
        TypeB const * valueB;
        // ... more types
      }

      arg_adapter(TypeA const & value) : type(fmtA), valueA(&value) {}
      arg_adapter(TypeB const & value) : type(fmtB), valueB(&value) {}
      // ...
  }

它们应该用于以下方法:

  Convert(const_arg_adapter from, arg_adapter to)

TypeX 有多个(大约 5 个,可能会更多),其中大部分是原始的。这是为了避免维护不同的原型。

现在我的问题 ;-)

有没有办法让 const-ness 成为模板参数? 我的目标是只维护一个结构,即

template <Qualifier CONSTNESS>
struct arg_adapter_t
{
   ...
   CONSTNESS TypeA * valueA;
   ...
}

【问题讨论】:

    标签: c++ templates qualifiers


    【解决方案1】:

    你可以让它接受metafunction,你可以应用任何你喜欢的转换

    template<template<typename> class F>
    struct arg_adapter
    {
        EArgType type;  // fmtA, fmtB, ...
    
        union
        {
          typename F<TypeA>::type * valueA;
          typename F<TypeB>::type * valueB;
          // ... more types
        };
    
        arg_adapter(typename F<TypeA>::type & value) : type(fmtA), valueA(&value) {}
        arg_adapter(typename F<TypeB>::type & value) : type(fmtB), valueB(&value) {}
        // ...
    };
    
    typename arg_adapter<boost::add_const> const_adapter;
    typename arg_adapter<boost::mpl::identity> nonconst_adapter;
    

    或接受metafunction class 以获得更大的灵活性(包括使F 具有arg_adapter 不知道的默认参数等的能力。

    template<typename F>
    struct arg_adapter
    {
        EArgType type;  // fmtA, fmtB, ...
    
        union
        {
          typename apply<F, TypeA>::type * valueA;
          typename apply<F, TypeB>::type * valueB;
          // ... more types
        };
    
        arg_adapter(typename apply<F, TypeA>::type & value) : type(fmtA), valueA(&value) {}
        arg_adapter(typename apply<F, TypeB>::type & value) : type(fmtB), valueB(&value) {}
        // ...
    };
    
    typename arg_adapter< lambda< boost::add_const<_> >::type > const_adapter;
    typename arg_adapter< lambda< boost::mpl::identity<_> >::type > nonconst_adapter;
    

    【讨论】:

    • 也许比添加一些typedef 可以避免重复typename apply&lt;F, TypeA&gt;::type 太多:)
    • @Matthieu 在 C++0x 中,我们可以直接说 apply&lt;F, TypeA&gt;&amp;。我会喜欢模板别名:)
    • 我也会,我也会 :) 我急切地等待模板别名和可变参数模板,只是想知道哪个编译器会先实现它:/
    【解决方案2】:

    我偶然发现了一种使用 Alexandrescu 在“现代 C++ 设计”中提出的类型选择理念的更好方法:

    这是类型选择器:

    template<bool flag, typename T, typename U>
    struct Select { typedef T Result; }
    
    template<typename T, typename U>
    struct Select<false, T, U> { typedef U Result; }
    

    您的班级将如下所示:

    template<bool isConst>
    struct arg_adapter
    {
      // define A and B as const or non-const
      typedef typename Select<isConst, const TypeA, TypeA>::Result A;
      typedef typename Select<isConst, const TypeB, TypeB>::Result B;
    
      EArgType type;  // fmtA, fmtB, ...
    
      union
      {
        A * valueA; // this is either const TypeA* oder TypeA* depending on
                    // your choice of the isConst template parameter
        B * valueB;
        // ... more types
      }
    
      arg_adapter(A & value) : type(fmtA), valueA(&value) {} // same here with ref
      arg_adapter(B & value) : type(fmtB), valueB(&value) {}
      // ...
    }
    

    为方便起见,您可以使用 typedef:

    struct nonconst_adapter : public arg_adapter<false> {};
    
    struct const_adapter : public arg_adapter<true> {};
    

    这是我使用简单类型特征的旧答案:

    template<typename TypeTraits>
    struct arg_adapter
    {
      typedef typename TypeTraits::T T;
      void bar(T a) { ... } // by value/reference
      void bar(T* a) { ... } // by pointer
    }
    
    template<typename K>
    struct NonConstTraits {
      typedef K T;
    }
    
    template<typename K>
    struct ConstTraits {
      typedef const K T;
    }
    
    template<typename K>
    struct nonconst_adapter : public arg_adapter<NonConstTraits<K> > {};
    
    template<typename K>
    struct const_adapter : public arg_adapter<ConstTraits<K> > {};
    

    【讨论】:

    • 感谢您的回复 - 它很好地说明了 Johannes 使用 boost 的解决方案的作用。 --- 我最终没有使用它,因为所有 typedef 的代码量都是相同的(在添加的情况下,无论如何都必须更新其他一些地方)。尽管如此,我还是对 TMP 更有信心了。
    • 仅供参考——从 C++11 标准开始,您不再需要定义自己的 Select,因为 std::conditional 正是这样做的。
    【解决方案3】:

    也许我没听懂,但你为什么不能用

    Convert(**const** arg_adapter from, arg_adapter to)
    

    声明一个typedef来简化工作

    【讨论】:

    • "指向的对象的常量是模板参数的一个属性。"这与这里的 const 指针无关。
    • 我需要用(const TypeA &amp;, TypeB &amp;) 调用Convert,而arg_adapter 没有const TypeA &amp; 的CTor。
    猜你喜欢
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    相关资源
    最近更新 更多