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?

8
  • 4
    Sure you don't have an unwanted using namespace std; somewhere this code is included? Commented May 1, 2015 at 18:07
  • 1
    Try this->set(target);. Commented May 1, 2015 at 18:08
  • 1
    @Michael See here please: std::set Commented May 1, 2015 at 18:10
  • 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. Commented May 1, 2015 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. Commented May 1, 2015 at 18:16

1 Answer 1

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); }
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.