模板扣除在堆上失败但在堆栈上工作

时间:2018-06-19 08:31:46

标签: c++ templates c++17

我的模板类有问题。 当我在堆栈上实例化该类时,它可以正常工作。 当我在堆上实例化同一个类时,它会失败。 (论据演绎) 我不明白为什么......

信息:我正在使用带有c ++ 17的gcc 7.2.0。

这里有一个例子:

#include <iostream>
#include <cstdlib>
#include <memory>

template <class ReturnType, class ClassName, class... Args>
class MethodPtr
{
public:
    typedef ReturnType (ClassName::*Method)(Args...);

    MethodPtr(ClassName* ptr, Method m) : _p(ptr), _m(m)
    {
        (ptr->*m)(4);
    }

    ClassName* _p;
    Method _m;
};

class Example
{
public:
    Example()
    {
        dotest(this, &Example::func);
    }

    template <class Ptr, class Func>
    void dotest(Ptr ptr, Func func)
    {
        // works
        MethodPtr(ptr, func);

        // don't works
        //std::make_unique<MethodPtr>(ptr, func);
        //new MethodPtr(ptr, func);

        //works
        std::make_unique<decltype(MethodPtr(ptr, func))>(ptr, func);
        new decltype(MethodPtr(ptr, func))(ptr, func);
    }

    void func(int i)
    {
        std::cout << i << std::endl;
    }
};

int main()
{
    Example example;
}

你有解决方案来避免decltype吗?

谢谢,

3 个答案:

答案 0 :(得分:21)

new MethodPtr(ptr, func)失败的事实确实是编译器错误。根据{{​​3}}:

  

也可以在中使用推断类类型的占位符    new-expression new-type-id type-id 中的 type-specifier-seq ,   或者作为显式类型转换中的 simple-type-specifier   (功能符号)([expr.type.conv])。推断的占位符   类类型不应出现在任何其他上下文中。

正如您所看到的,对新表达式明确表示赞成,并对未明确允许的任何内容进行全面禁止。因此,make_unique 无法获得占位符。

除非您可以迁移到已修复此问题的GCC版本(或者您只需要使用make_unique),否则无法避免decltype。尝试引入类型别名以减轻不便。

答案 1 :(得分:6)

在最新的gcc和clang中它起作用了 - new MethodPtr(ptr, func)。所以对于gcc7.2 - 这是一个bug。

对于unique_ptr(new MethodPtr(ptr, func)) - 它不起作用 - 因为在C ++中 - 在此级别,MethodPtr* - 我们无法区分unique_ptr<MethodPtr[]>unique_ptr<MethodPtr> - 因此无法推断

答案 2 :(得分:3)

here。简单地传递MethodPtr(类模板)作为函数模板(std::make_unique)的非模​​板类型参数从未被允许,并且类模板参数推导没有改变它。

new MethodPtr{ptr, func};通过查看参考资料而起作用,但我不能说出与new MethodPtr(ptr, func);

不同的原因