【问题标题】:Omitting class template methods based on template parameter基于模板参数省略类模板方法
【发布时间】:2014-03-06 05:22:14
【问题描述】:

我也看到了我的问题的各种形式的回答/答复,但我仍然很难弄清楚如何省略我的编译器状态模棱两可的函数。

我有一个旨在处理数据流的类。我重载了 = 和 += 运算符,以便流类可以通过将其转换为模板类型 T 来使用其他类型的数据。

template<typename T>
class TStream
{
private:

    typedef TBuffer<T> stream_buffer;
    stream_buffer mStream;

public:

    TStream();
    TStream(const TStream &rhs);
    TStream::~TStream();

    unsigned int Size() const;
    unsigned int ByteStreamLength() const;
    void     Clear();

  // some methods omitted for brevity

    const T&operator[](unsigned int idx);
    const T*operator[](unsigned int idx) const;

    TStream<T> &operator=(const TStream &rhs);
    TStream<T> &operator=(T const);
    TStream<T> &operator=(unsigned char);
    TStream<T> &operator=(bool);
    TStream<T> &operator=(double);

  // rest omitted for brevity
};

这样做

TStream<unsigned char> ByteStream

造成歧义
operator=(unsigned char).

如果 T = unsigned char,我基本上希望 operator=(unsigned char) 被省略。

这篇文章似乎提供了一种方法: http://www.drdobbs.com/function-overloading-based-on-arbitrary/184401659

但是很难遵循它,因为我不想改变我的返回类型。

我通常像这样使用 TStream:

   TStream<unsigned byte> ByteStream;
   ByteStream+= int
   ByteStream+= char

... 等等,我以同样的方式重载 +=。我推断传入的大小并将其转换为 T。我这样做是为了避免为简单的 POD 案例传递一个 void * 和一个长度参数。

【问题讨论】:

  • 这是什么? TStream::~ptiStream();
  • @BrianBi:哎呀,错字了。我正在修剪帖子的代码,那是模板类的旧名称。我进行了编辑以修复它。
  • @BrianBi:因为泛型 T 可能是 unsigned char 类型,我希望能够附加到流中,例如 int 类型。在这种情况下,流将消耗 sizeof(int) ... int 类型将转换为 sizeof(int) 字节并添加到流中。
  • 是的,对不起,我看错了你的代码。我删除了我的评论。
  • 您可能希望 (a) 为该参数使用 T const&amp;,并 (b) 指定您正在使用的工具链。

标签: c++ templates specialization


【解决方案1】:

有一个简单的方法,一个合法的方法。

简单的方法是在相关函数上使用 SFINAE。可悲的是,由于这会导致没有有效专业化的功能模板,因此从技术上讲,这是一个格式错误的程序(不需要诊断)。所以避免这种情况。

合法的方式是使用 CRTP。

template<typename D, typename T, typename U>
struct implement_operator_plus_equals {
  implement_operator_plus_equals() {
    static_assert( std::is_base_of<implement_operator_plus_equals, D>::value, "CRTP failure" );
  }
  D* self() { return static_cast<D*>(this); }
  D const* self() const { return static_cast<D const*>(this); }

  typedef D Self;

  Self& operator+=( U u ) {
    static_assert( (sizeof(U)%sizeof(T)) == 0, "Non integer number of Ts in a U" );
    T* b = reinterpret_cast<T*>(&u);
    T* e = b + sizeof(U)/sizeof(T);
    for (T* it = b; it != e; ++it) {
      self()->consume(*it);
    return *self();
  }
};
template<typename D, typename T>
struct implement_operator_plus_equals<D,T,T> {
  implement_operator_plus_equals() {
    static_assert(
      std::is_base_of<implement_operator_plus_equals, D>::value, "CRTP failure"
    );
    // Have an operator+= that cannot be called, so using ...::operator+= is legal,
    // but mostly harmless:
    class block_call {};
    void operator+=( block_call ) {}
  }
};

然后使用它:

template<typename D,typename T>
struct plus_equals_helper:
  public implement_operator_plus_equals< TStream<T>, T, int >,
  public implement_operator_plus_equals< TStream<T>, T, unsigned char >,
  public implement_operator_plus_equals< TStream<T>, T, bool >,
  public implement_operator_plus_equals< TStream<T>, T, double >
{
  // move += down from parents (to fix problem OP reported):
  using implement_operator_plus_equals< TStream<T>, T, int >::operator+=;
  using implement_operator_plus_equals< TStream<T>, T, unsigned char >::operator+=;
  using implement_operator_plus_equals< TStream<T>, T, bool >::operator+=;
  using implement_operator_plus_equals< TStream<T>, T, double >::operator+=;
};

template<typename T>
class TStream:
  public plus_equals_helper< TStream<T>, T >
{
public:
  void consume( T t ) { /* code */ }
  using plus_equals_helper<TStream<T>, T>::operator+=;
  TStream const& operator+=( T t ) { consume(t); return *this; }
};

这是合法的,因为什么都不做的专精完全没问题。

另一方面,所有模板函数必须至少有一个有效的特化的规则是相当模糊的,如果你违反它,通常不会发生真正的坏事。因此,您可以使用第二个未使用的默认参数 SFINAE 禁用您的方法。

【讨论】:

  • 你在上次的 sn-p 中有一个流浪的template&lt;typename T&gt;
  • 我的交叉编译器似乎不支持 std::is_base_of
  • @Eric 这只是一个健全性检查——static_assert 如果你做了危险的事情会警告你。如果你愿意,你可以自己实现它。
  • @jrok Darn template 侥幸逃脱了 T
  • 另外,possible workaround 表示“没有有效的专业化规则”?
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-02
  • 1970-01-01
相关资源
最近更新 更多