1

I have a compile error in the following code. It seems that the compiler interprets class method set as a template which - at first glance - is completely unrelated to my code.

#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


};

Compiler gives the following error:

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

But I think it's because it thinks that set is a template:

/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;

I do not understand why the compiler tries to instantiate that template for method set and not just call method set. How can I resolve this name confusion?

David Hammen
  • 32,454
  • 9
  • 60
  • 108
Michael
  • 7,407
  • 8
  • 41
  • 84
  • 4
    Sure you don't have an unwanted `using namespace std;` somewhere this code is included? – πάντα ῥεῖ May 01 '15 at 18:07
  • 1
    Try `this->set(target);`. – lisyarus May 01 '15 at 18:08
  • @πάνταῥεῖ: Yes, that's the case. I did an edit. But what is this `set` and why is it preferred against the class method? – Michael May 01 '15 at 18:09
  • 1
    @Michael See here please: [`std::set`](http://en.cppreference.com/w/cpp/container/set) – πάντα ῥεῖ May 01 '15 at 18:10
  • @πάνταῥεῖ: I know `std::set` but what exactly is the rule to tell whether `set` is interpreted as `this->set` or `std::set` in my case? – Michael May 01 '15 at 18:13
  • 2
    @πάνταῥεῖ This code is wrong even without `using namespace std;`. The base class is dependent, so it's not searched unless you do `this->set`. – Brian Bi May 01 '15 at 18:13
  • 1
    @πάνταῥεῖ No, that's not a duplicate. Sure the OP shouldn't be using namespace std, but that alone won't solve the problem. He'll run into additional errors once he fixes that. – Praetorian May 01 '15 at 18:16
  • possible duplicate of [Why can't I use variable of parent class that is template class?](http://stackoverflow.com/questions/10171242/why-cant-i-use-variable-of-parent-class-that-is-template-class) – Oktalist May 01 '15 at 19:26

1 Answers1

6

You will still have problems even if you get rid of that nasty using namespace std. The problem is that member function set may not exist in all instantiations. The code in the question uses set as an unqualified, non-dependent name. This means two things:

  • The compiler will try to resolve set at the point where the template is defined.
  • The compiler will not look into the base class ReduceScalar<T> for member function set. It can't because that member might not exist for all instantiations.

End result: The code doesn't compile. The solution is to turn that non-dependent name into a dependent name. This defers resolution of dependent names until the template instantiation. One way to do this is to explicitly use this (which is a dependent name).

template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
    ReduceSum(T* target) { this->set(target); }
};

Alternatively, you can use the using declaration (very different from the using directive):

template <class T>
class ReduceSum : public ReduceScalar<T>
{
public:
    using ReduceScalar<T>::set;
    ReduceSum(T* target) { set(target); }
};
David Hammen
  • 32,454
  • 9
  • 60
  • 108