I have some code that I want to convert from using overloaded functions to using variadic template arguments.
The existing code has multiple templated functions for the different parameter counts:
#include <iostream>
#include <string>
struct Boo
{
Boo(const std::string& name)
{
std::cout << "Boo constructor: " << name << std::endl;
};
static std::string CreateName(const std::string& name)
{
return "BooID:" + name;
}
};
struct Foo
{
Foo(const std::string& name)
{
std::cout << "Foo constructor: " << name << std::endl;
};
};
template <typename T>
T Construct(const std::string& name)
{
return T(T::CreateName(name));
}
template <typename T>
T Construct(const std::string& name1, const std::string& name2)
{
return T(T::CreateName(name1, name2));
}
// Class Foo doesn't have CreateName available
template<>
Foo Construct<Foo>(const std::string& name)
{
return Foo{"ID:" + name};
}
int main()
{
Construct<Boo>(std::string("123"));
Construct<Foo>(std::string("456"));
}
This outputs:
Boo constructor: BooID:123
Foo constructor: ID:456
If I try to replace the two templated Construct()
functions with a single variadic templated version then I can't work out how I should specify the special version just for the Foo
class (tried on GCC 4.9.2, 8.1 and Visual Studio 2015).
template <class T, typename ...Args>
T Construct(Args... args)
{
return T(T::CreateName(args...));
}
// Class Foo needs some extra information when constructed with strings...
template<>
Foo Construct<Foo>(const std::string& name)
{
return Foo{"ID:" + name};
}
Fails with the compiler trying to use the variadic template version (so no CreateName
in Foo
).
I can get it to work by making a generic template and using std::enable_if_t
to restrict the types:
template <class T, typename ...Args>
T Construct(Args... args)
{
return T(T::CreateName(args...));
}
// Class Foo needs some extra information when constructed with strings...
template<typename T, typename = std::enable_if_t<std::is_base_of<Foo, T>::value>>
T Construct(const std::string& name)
{
return T{"ID:" + name};
}
Which isn't as easy to read as the original template<> Foo Construct<Foo>(...)
version. Is using std::enable_if_t
with variadic template the only option, or is there some way of overloading that will give the desired behaviour?
Aucun commentaire:
Enregistrer un commentaire