Компилятор путает имя (несвязанного) шаблона с именем метода

У меня есть ошибка компиляции в следующем коде. Кажется, что компилятор интерпретирует метод класса 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


};

Компилятор выдает следующую ошибку:

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

Но я думаю, это потому, что он считает, что 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;

Я не понимаю, почему компилятор пытается создать экземпляр этого шаблона для метода set, а не просто вызвать метод set. Как я могу решить эту путаницу имен?


person Michael    schedule 01.05.2015    source источник
comment
Уверены, что у вас нет нежелательного using namespace std; где-то, где этот код включен?   -  person πάντα ῥεῖ    schedule 01.05.2015
comment
Попробуйте this->set(target);.   -  person lisyarus    schedule 01.05.2015
comment
@πάνταῥεῖ: Да, это так. Я сделал правку. Но что это за set и почему он предпочтительнее метода класса?   -  person Michael    schedule 01.05.2015
comment
@Michael Смотрите здесь, пожалуйста: std::set   -  person πάντα ῥεῖ    schedule 01.05.2015
comment
@πάνταῥεῖ: я знаю std::set, но какое именно правило определяет, интерпретируется ли set как this->set или std::set в моем случае?   -  person Michael    schedule 01.05.2015
comment
@πάνταῥεῖ Этот код неверен даже без using namespace std;. Базовый класс является зависимым, поэтому он не ищется, пока вы не сделаете this->set.   -  person Brian Bi    schedule 01.05.2015
comment
@ πάνταῥεῖ Нет, это не дубликат. Конечно, OP не должен использовать пространство имен std, но само по себе это не решит проблему. Он столкнется с дополнительными ошибками, как только исправит это.   -  person Praetorian    schedule 01.05.2015


Ответы (1)


У вас все равно будут проблемы, даже если вы избавитесь от этого противного 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); }
};

В качестве альтернативы вы можете использовать объявление using (сильно отличающееся от директивы using):

template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
    using ReduceScalar<T>::set;
    ReduceSum(T* target) { set(target); }
};
person David Hammen    schedule 01.05.2015