I'm trying to implement the iostream operators as a friend function to a variadic class template.
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInformation {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInformation( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInformation<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInformation<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInformation& c );
friend std::istream& operator>> ( std::istream& in, StudentInformation& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
And for some reason I'm still getting a linker error. Even when the overloads are defined in the header I'm still getting a linker error as if they were defined in a cpp file. Any thoughts?
Even when I try this approach: Declaring a prototype of the class first, then declaring prototypes of the overloaded operators, then declaring the class, then defining the friend overloaded operators:
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInfo;
template<typename... Args>
std::ostream& operator<<( std::ostream& out, const StudentInfo<Args...>& c );
template<typename... Args>
std::istream& operator>>( std::istream& in, StudentInfo<Args...>& c );
template<typename... Args>
class StudentInfo {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInfo( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInfo<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInfo<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInfo& c );
friend std::istream& operator>> ( std::istream& in, StudentInfo& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
I'm still getting a linker error. I could make these a part of the class; but I don't want that behavior. I want them to be defined outside of the class. As it currently stands; everything in the class right now is public only for testing, but once this class works as intended; everything in it will be private as this class will be a friend to another class; where the owning class will have access to all of its private information. I don't know how to get around or resolve this linker error problem.
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class StudentInfo<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<int,class std::allocator<int> > > const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$StudentInfo@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V12@HV12@V?$vector@HV?$allocator@H@std@@@2@@@@Z) referenced in function _main