Reputation: 655
I am new to template function with variadic arguments. The code , inspired by a Codeview article , don't compile at the CreateBook(), need help.
I want to create an object using factory method and template .
using namespace std;
template<class T>
class bar
{
public:
template<class... Args>
static bar<T> CreateBook(Args&&... args)
{
return bar<T>(std::forward<Args>(args)...); // Don't compile here
}
T get()
{
return val;
}
private:
bar(const T& t) :val(t) {}
T val;
};
struct book
{
string name;
int phone;
book(string s, int t) : name(s), phone(t) {}
};
void print(bar<book> k)
{
cout << k.get().name << " " << k.get().phone << endl;
}
int main()
{
bar<book> b = bar<book>::CreateBook("Hello World",91520);
print(b);
return 0;
}
Upvotes: 2
Views: 85
Reputation: 870
Every problem can be solved by adding one more layer.
First lets isolate the job of Factory. It should do only one task. Factory
provides an interface on top on the underlying object of type T
.
template <typename T>
class Factory
{
public:
// prefer copy and move, if you have C++11
Factory(Type d) : data(std::move(d)) {}
// const getter
T get() const { return data; };
// non-const reference getter, for modifications
T & get() { return data; };
private:
T data;
};
Now lets create a helper function on top of it, to help us manage and allocate objects. The job of this MakeObject
is to make an object and hand over the object to a manager, i.e. Factory
. It then returns the instance of that managed object.
template<typename Object, typename ... Args>
Factory<Object> MakeObject(Args && ... args)
{
return Factory<Object>{ Object{ std::forward<Args>(args) ... } };
}
Now we can combine the two of them independently, to create something that is desired.
#include <iostream>
template <typename T>
class Factory
{
public:
Factory(Type d) : data(std::move(d)) {}
T get() const { return data; };
T & get() { return data; };
private:
T data;
};
template<typename Object, typename ... Args>
Factory<Object> MakeObject(Args && ... args)
{
return Factory<Object>{ Object{ std::forward<Args>(args) ... } };
}
struct book
{
std::string name;
int phone;
book(std::string s, int t) : name(s), phone(t) {}
};
void print(Factory<book> const & k)
{
std::cout << "[ Factory ] : " << k.get().name << ", " << k.get().phone << std::endl;
}
int main()
{
auto obj = MakeObject<book>("Hello World", 91520);
print(obj);
return 0;
}
I didn't use the static
function CreateBook
because the intent is not clear. If you really want to use static
, now you have the decoupled code, and it can be implemented and tested independently in the class Factory
.
Upvotes: 0
Reputation: 1275
I tried to compile your code and I get errors something like no matching function for call to 'bar<book>::bar(const char [12], int)'
therefore I added T(...)
to the line marked as "Don't compile here."
and it worked! Now the code looks something like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <utility>
using namespace std;
template<class T>
class bar
{
public:
template<class... Args>
static bar<T> CreateBook(Args&&... args)
{
return bar<T>(T(std::forward<Args>(args)...)); // Fixed this line.
}
T get()
{
return val;
}
private:
bar(const T& t) :val(t) {}
T val;
};
struct book
{
string name;
int phone;
book(string s, int t) : name(s), phone(t) {}
};
void print(bar<book> k)
{
cout << k.get().name << " " << k.get().phone << endl;
}
int main()
{
bar<book> b = bar<book>::CreateBook("Hello World",91520);
print(b);
return 0;
}
Upvotes: 1
Reputation: 5156
See this code. Your bar constructor should handle pack argument too.
template<class... X>
bar(X... x) :val(x...) {}
Upvotes: 1