【问题标题】:Coercing template class with operator T* when passing as T* argument of a function template当作为函数模板的 T* 参数传递时,使用运算符 T* 强制模板类
【发布时间】:2010-09-16 19:14:17
【问题描述】:

假设我有一个这样的函数模板:

template<class T>
inline
void
doStuff(T* arr)
{
  // stuff that needs to use sizeof(T)
}

然后在另一个.h 文件中,我有一个模板类Foo,它有:

public: operator T*() const;

现在,我意识到这些是不同的 T。但是如果我在堆栈上有一个变量Foo&lt;Bar&gt; f,那么将它强制为任何类型的指针的唯一方法是调用operator T*()。然而,如果调用doStuff(f),GCC 会抱怨doStuff 不能使用Foo&lt;Bar&gt;,而不是自动使用运算符T*() 强制转换为Bar*,然后使用Bar 将函数模板特化为T

我可以做些什么来使用两个模板来完成这项工作?还是模板函数的参数必须是真正的指针类型,或者带有强制运算符的模板类被传递给非模板函数?

【问题讨论】:

    标签: c++ templates coercion


    【解决方案1】:

    我不确定为什么转换不起作用,但您可以使用重载来解决问题

    
    template 
    inline
    void 
    doStuff(T& arrRef)
    {
      doStuff(&arrRef);
    }
    

    【讨论】:

    • 取消引用通常是不好的风格。我知道 hack 有其价值,但只是非常谨慎地使用。
    • 另外,它根本不正确。语法上是因为你没有在任何地方定义 T,语义上是因为 Foo.operator&() 不会返回 T* 而是 Foo*.
    【解决方案2】:

    嗯,T* 并不是你认为的与 T 不同的类型。指针是一个类型限定符。我不确定标准对此有何规定,但我会说,由于变量已经是 T 类型,它不会尝试再次转换。如果你想做一些自定义的东西来获取指针,重载 & 运算符。

    【讨论】:

    • 你真的不想重载 operator&()。请参阅 Google 最佳做法了解原因。
    【解决方案3】:

    GCC 是正确的。在模板参数中,只考虑完全匹配,不考虑类型转换。这是因为否则可能必须考虑无限(或至少指数)数量的转换。

    如果 Foo 是您要运行的唯一其他模板,最好的解决方案是添加:

    template<typename T> inline void doStuff(const Foo<T>& arr) {
        doStuff(static_cast<T*>(arr));
    }
    

    如果您在使用大量模板时遇到此问题,这个问题应该可以解决:

    #include <boost/type_traits/is_convertible.hpp>
    #include <boost/utility/enable_if.hpp>
    template<template <typename> class T, typename U> inline typename boost::enable_if<typename boost::is_convertible<T<U>, U*>::type>::type doStuff(const T<U>& arr) {
        doStuff(static_cast<U*>(arr));
    }
    

    虽然有点冗长;-)

    【讨论】:

      【解决方案4】:

      这可能值得一试:

      doStuff<Bar>(f);
      

      我认为这会导致编译器期望 T* 为 Bar*,然后使用 Foo 的运算符 T*() 执行强制转换,但我不能说我已经尝试过了。

      【讨论】:

      • 正确。编译器抱怨因为模板参数推导失败。一旦你提供了论据,就没有 TAD。此时,编译器知道转换序列的目标类型和目标类型。
      【解决方案5】:

      Leon 的想法可能是最好的。但在紧要关头,您也可以显式调用强制转换运算符:

      doStuff(static_cast<Bar*>(f));
      

      【讨论】:

        猜你喜欢
        • 2013-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-10
        • 1970-01-01
        • 1970-01-01
        • 2014-07-24
        相关资源
        最近更新 更多