编译器将(不相关的)模板的名称与方法名称混淆

Mic*_*ael 1 c++ templates dependent-name

我在以下代码中有一个编译错误.似乎编译器将类方法解释set为一个模板 - 乍一看 - 与我的代码完全无关.

#include <cassert>
#include <limits>

using namespace std;

template <class T>
class ReduceScalar{

    public:
        T get() { return *r; };
        void set(T t) { *r = t; };
        void set(T* t) { r = t; };

    private:
        T* r;

};

template <class T>
class ReduceSum : public ReduceScalar<T>
{
    public:
        ReduceSum(T* target) { set(target); set(0); } // COMPILE ERROR


};
Run Code Online (Sandbox Code Playgroud)

编译器给出以下错误:

../test/../io/scalarreducers.h:34:26: error: use of class template 'set' requires template arguments
                ReduceSum(T* target) { set(target); set(0); }
Run Code Online (Sandbox Code Playgroud)

但我认为这是因为它认为这set是一个模板:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tree:685:71: note: template is declared here
        template <class, class, class> friend class _LIBCPP_TYPE_VIS_ONLY set;
Run Code Online (Sandbox Code Playgroud)

我不明白为什么编译器试图为方法实例化该模板set而不仅仅是调用方法set.我怎样才能解决这个名称混乱?

Dav*_*men 6

即使你摆脱了这种讨厌,你仍然会遇到问题using namespace std.问题是成员函数set可能不存在于所有实例中.问题中的代码set用作不合格的非依赖名称.这意味着两件事:

  • 编译器将尝试set在定义模板的位置解析.
  • 编译器不会查看ReduceScalar<T>成员函数的基类set.它不能,因为该成员可能不存在于所有实例化中.

最终结果:代码无法编译.解决方案是将该非依赖名称转换为依赖名称.这推迟了依赖名称的解析,直到模板实例化为止.一种方法是明确使用this(这是一个依赖名称).

template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
    ReduceSum(T* target) { this->set(target); }
};
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用using声明(与using指令非常不同):

template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
    using ReduceScalar<T>::set;
    ReduceSum(T* target) { set(target); }
};
Run Code Online (Sandbox Code Playgroud)