declare template friend function of template class

29,894

Solution 1

You need a few forward declarations:

template <typename T>
class Obj;

template <typename T>
Obj<T> make_obj(T t);

template <typename T>
class Obj {
private:
    T & t;
    Obj (T & t) : t(t) { }
    Obj() = delete;

    friend Obj make_obj<T>(T t);
};

template <typename T>
Obj<T> make_obj(T t) { 
    return Obj<T>(t);
}

live example

And BTW: I don't think you really want T & t; for your class' member variable. Probably T t; is a better choice ;)

Solution 2

With the automatic return type syntax, you only need to forward declare the function and everything works. Here is an example

template <typename T>
auto make_obj(T t);

template <typename T>
class Obj {
private:
    T & t;
    Obj (T & t) : t(t) { }
    Obj() = delete;

    friend auto make_obj<T>(T t);
};

template <typename T>
auto make_obj(T t) {
    return Obj<T>{t};
}

int main() {
    make_obj(1);
    return 0;
}

https://ideone.com/3k86gx

Share:
29,894
Ryan Haining
Author by

Ryan Haining

cppitertools writing python in c++ for the greater good for (auto&amp;&amp; i : range(1, 10, 2)) { ... } for (auto&amp;&amp; [i, e] : enumerate(vec)) { ... } for (auto&amp;&amp; n : imap([] (int i) { return i*i; }, vec)) { ... }

Updated on November 21, 2020

Comments

  • Ryan Haining
    Ryan Haining over 3 years

    I have a class template Obj and a function template make_obj. Obj has a private single constructor defined, which takes a reference to its templated type to bind to.

    template <typename T>
    class Obj {
      private:
        T& t;
        Obj(T& t)
            : t{t}
        { }
    };
    
    template <typename T>
    Obj<T> make_obj(T& t) { 
        return {t};
    }
    

    What I want is to declare the make_obj function a friend so that it can create Obj's, but no one else can (except via the copy ctor).


    I have tried several friend declaration including

    friend Obj make_obj(T&);
    

    and

    template <typename T1, typename T2>
    friend Obj<T1> make_obj(T2&);
    

    The latter being a less than desirable attempt at making all template instantiations of make_obj friends of the Obj class. However in both of these cases I get the same error:

    error: calling a private constructor of class 'Obj<char const[6]>'
        return {t};
               ^
    
    note: in instantiation of function template specialization
          'make_obj<const char *>' requested here
        auto s = make_obj("hello");
                 ^
    

    trying to do make_obj("hello"); for example purposes.

    How can I allow only make_obj access to Obj's value contructor?

  • David Rodríguez - dribeas
    David Rodríguez - dribeas almost 11 years
    You went all the 9 yards and then dropped the ball... the friend should not be a template, but a template specialization :) [Only make_obj<A> needs access to Obj<A>, no need to enable access to make_obj<Z>!] --for the record: friend Obj<T> make_obj<T>(T t); instead of befriending the template
  • Daniel Frey
    Daniel Frey almost 11 years
    @DavidRodríguez-dribeas You are right. I fixed the answer but not the live example to leave the "old" way as a reference. Thanks!
  • Martin Pecka
    Martin Pecka about 4 years
    Wow, I wouldn't say that substituting T return type with auto would help, but it does!
  • 김선달
    김선달 over 3 years
    If the return type of a friend function relies on the class' scope type aliases, this is the only way.