Search code examples
c++templatesfriend-function

"No instance of overloaded function" error with static friend template function


I have a class A that is trying to call a nonmember function DoTheThing. DoTheThing is a friend of class A so that it can call a private member function TheThing of A. DoTheThing is a template function so that it can call TheThing in multiple user-defined classes. Because the error references an overloaded function, I believe that I am redefining DoTheThing within A, but I cannot figure out how to fix this error.

#include <iostream>
#include <vector>

template<typename Component>
    requires requires (std::vector<double>& vec, int i) {Component::TheThing(vec, i); }
    static void DoTheThing(std::vector<double>& vec, int i) {
        Component::TheThing(vec, i);
    }


class A {
    template<class Component>
    friend void DoTheThing(std::vector<double>& vec, int i);
public:
    A() {
        vec_.resize(10, 5);
        DoTheThing<A>(vec_, 7); // Error: no instance of overloaded function
    }
private:
    static void TheThing(std::vector<double>& vec, int i) {
        vec[i] = vec[i] * i;
    }


    std::vector<double> vec_;
};

Am I redefining DoTheThing? How do I make the non-member DoTheThing a friend of A? How do I call DoTheThing in the constructor of A?


Solution

  • You are not constraining the friend declaration with an ad-hoc requires clause, so you are actually not granting friendship to the same DoTheThing function you want. You need to replicate the requires clause in the friend declaration as well:

    class A {
        template<class Component>
        requires requires (std::vector<double>& vec, int i) {Component::TheThing(vec, i); }
        friend void DoTheThing(std::vector<double>& vec, int i);
    // ...
    };
    

    Here's a demo.


    However, you should name this concept, and the usage will be simpler:

    template<typename Component>
    concept CanDoThing = requires (std::vector<double>& vec, int i) { 
      Component::TheThing(vec, i); 
    };
    
    template<CanDoThing Component>
    static void DoTheThing(std::vector<double>& vec, int i) {
      Component::TheThing(vec, i);
    }
    
    class A {
      template<CanDoThing Component>
      friend void DoTheThing(std::vector<double>& vec, int i);
    // ...
    };