I have some trouble getting this to work. Here is a MVCE of my problem that passes the compilation phase
template<typename T>
struct foo
{
using type = T;
friend type bar(foo const& x) { return x.X; }
foo(type x) : X(x) {}
private:
type X;
};
template<typename> struct fun;
template<typename T> fun<T> bar(foo<T> const&, T); // forward declaration
template<typename T>
struct fun
{
using type = T;
friend fun bar(foo<type> const& x, type y)
{ return {bar(x)+y}; }
private:
fun(type x) : X(x) {}
type X;
};
int main()
{
foo<int> x{42};
fun<int> y = bar(x,7); // called here
};
The forward declaration is required for the compiler to resolve the call in main()
(see this answer for the reason). However, the compiler now complains in the linking/loading phase:
Undefined symbols for architecture x86_64: "fun bar(foo const&, int)", referenced from: _main in foo-00bf19.o ld: symbol(s) not found for architecture x86_64
even though the function is defined in the friend declaration. If instead, I move the definition outside of that of struct func<>
, i.e.
template<typename T>
struct fun
{
using type = T;
friend fun bar(foo<type> const& x, type y);
private:
fun(type x) : X(x) {}
type X;
};
template<typename T>
inline fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
compilation fails with
foo.cc:29:10: error: calling a private constructor of class 'fun<int>'
{ return {bar(x)+y}; }
So, how can I get this to work? (compiler: Apple LLVM version 9.0.0 (clang-900.0.39.2), c++11)
Friend declaration inside of fun must match function template forward declaration, otherwise it will spawn an unrelated function:
template<typename TT> fun<TT> friend ::bar(foo<TT> const &, TT);
While definition should be placed outside:
template<typename T> fun<T> bar(foo<T> const& x, T y)
{ return {bar(x)+y}; }
The shorter code to demonstrate the problem would be:
void foo(void);
template<typename T>
struct bar
{
friend void foo(void) {}
};
int main()
{
foo(); // undefined reference to `foo()'
return 0;
}
In-class function definition will never be used:
17.8.1 Implicit instantiation [temp.inst]
- The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and
friends
;