【问题标题】:How to have the compiler deduce the return type of a templated method in C++11?如何让编译器推断 C++11 中模板化方法的返回类型?
【发布时间】:2017-01-27 03:30:45
【问题描述】:

我有一个模板化方法,其中返回类型将是 reinterpret_cast() 调用的结果。

class A {
    void *_ptr;
public:
    template<typename T>
    T buffer() { return reinterpret_cast<T>(_ptr); }
};

这种方式让我在调用这个函数时使用&lt;&gt;-syntax:

A a;
auto b = a.buffer<double *>();

我更喜欢在没有模板参数的情况下调用此方法,并让编译器根据变量类型推断返回类型。

A a;
double *out = a.buffer();

这可以通过返回类型扣除吗?

我尝试使用auto-&gt;-操作数和尾随返回类型语法

auto buffer() -> decltype(reinterpret_cast<T>(_ptr)) const 
     { return reinterpret_cast<T>(_ptr); }

但还是不行。

在 C++11 中有没有办法做到这一点?

【问题讨论】:

  • 但是可变类型是A。您的代码中没有关于返回类型的信息。你必须在某个地方定义它,即。 using type = double;
  • @Jaa-c 你能详细解释一下你的澄清要求吗?

标签: c++ templates c++11 methods return-type


【解决方案1】:

是的,但只能通过具有转换函数模板的代理类型:

struct BufferProxy {
  void* ptr;
  template<class T> operator T*() { return reinterpret_cast<T*>(ptr); }
};
BufferProxy buffer() { return BufferProxy{_ptr}; }

Example.

请注意,熟悉使用auto 进行返回类型推导的用户可能会对这种技术感到困惑:

auto out = a.buffer(); // out is BufferProxy 
auto* out = a.buffer(); // fails to compile; can't deduce 'auto*' from 'a.A::buffer()'

在 C++17 之前,您可以通过为 BufferProxy 提供已删除的复制构造函数(并可能通过聚合构造返回它:return {_ptr};)来阻止 auto out = a.buffer(); 编译,但用户仍然可以使用 auto&amp;&amp;从 C++17 开始,guaranteed copy elision 将使auto 表单再次工作。

【讨论】:

  • 要获得高质量的答案,请注意关于 auto 如何打破这一点会有所帮助,以及您可以采取哪些措施(即,将 operator* 设为 &amp;&amp; 过载:不完美,但有所帮助。更进一步,您可以将复制/移动设为私有(但这在 C++17 中不再有帮助)并与创建函数成为朋友)。
【解决方案2】:

我猜this answer是最优雅的。

无论如何,你也可以让类初始化你的指针,如下所示:

class A {
    void *_ptr;
public:
    template<typename T>
    void buffer(T **t) { *t = reinterpret_cast<T*>(_ptr); }
};

int main() {
    A a;
    double *b;
    a.buffer(&b);
}

这样,类型是从参数列表中推导出来的,您不必显式指定它。

【讨论】:

    【解决方案3】:

    你可能想要一个类似下面的类。这似乎提供了您想要做的大部分事情。

    我想知道的一个问题是如何确定存储到类中的指针是否为同一类型。所以我认为最好添加一个额外的方法来检查typeid() 使用hash_code() 方法。

    所以我想出了在他/她的回答中使用@ecatmur 的operator 想法的课程:

    class A {
        void    *_ptr;
        size_t  _ptrHash;
    
    public:
        template<typename T> operator T*() { return reinterpret_cast<T *>(_ptr); }
        template<typename T>
        void SetPtr(T *p) { _ptr = p; _ptrHash = typeid(*p).hash_code(); }
        template<typename T> bool operator == (T *p) { return p && typeid(*p).hash_code() == _ptrHash /* && p == _ptr */; }
    };
    

    相等运算符可以只检查上面的类型,或者如果取消注释附加检查,还可以检查指针的值。您可能只想检查类型。

    我用来测试的一个简单的演示函数如下:

    void funky1() {
        A a;
    
        double ddd[50] = { 0.0 };
        ddd[0] = 5.0; ddd[2] = 7.0;
    
        a.SetPtr(&ddd[0]);
    
        double *p = a;
        bool bb = a == p;
    
        long  lll[50] = { 0 };
        lll[0] = 5; lll[2] = 7;
    
        long *q = a;
        bb = a == q;
    
        a.SetPtr(&lll[0]);
        q = a;
    
        bb = a == q;
    }
    

    我使用调试器 Visual Studio 2013 逐步完成了这项工作,它看起来就像一个冠军。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      • 2015-12-14
      • 1970-01-01
      相关资源
      最近更新 更多