Объявлять функцию шаблона шаблона класса шаблона

У меня есть шаблонный класс Obj и make_obj. Obj имеет один определенный конструктор, который ссылается на свой шаблонный тип для привязки к.

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

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

Как вы можете видеть, этот конструктор является закрытым. Я хочу объявить функцию make_obj a friend, чтобы она могла создавать Obj, но никто не может (кроме как с помощью copy ctor).


Я пробовал несколько объявлений друзей, включая

friend Obj make_obj(T&);

и

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

Последнее является менее желательной попыткой сделать все шаблонные экземпляры make_obj друзей класса Obj. Однако в обоих случаях я получаю ту же ошибку:

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");
             ^

пытается сделать make_obj("hello"); для целей.

Как я могу разрешить только make_obj доступ к Obj конструктору значения?

Ответы

Ответ 1

Вам нужно несколько передовых объявлений:

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);
}

живой пример

И BTW: Я не думаю, что вы действительно хотите T & t; для переменной-члена вашего класса. Вероятно, T t; - лучший выбор;)

Ответ 2

С синтаксисом автоматического возврата, вам нужно только переслать объявление функции, и все работает. Вот пример

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