Is it possible to write something like this in C++11/14?
#include <iostream>
#include <vector>
template <typename T>
T Get();
template <typename T>
struct Data {
std::vector<T> data;
};
template <>
template <typename T>
Data<T> Get<Data<T>>() {
return Data<T>{{T{}, T{}}};
}
template <>
template <typename T>
std::vector<T> Get<std::vector<T>>() {
return std::vector<T>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
Overloading won't help in this case, since call to Get<...>()
will be ambiguious (see):
template <typename T>
Data<T> Get() {
return Data<T>{{T{}, T{}}};
}
template <typename T>
std::vector<T> Get() {
return std::vector<T>(3);
}
Any direction on how to overcome this are welcome.
There is workaround, that gives you something like this: do not specialize - overload:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
size_t Get(const T& data)
{
return 444;
}
template <typename T>
struct Data
{
std::vector<T> data;
};
template <typename T>
size_t Get(const Data<T>& data) {
return data.data.size();
}
int main() {
std::cout << Get<>(0) << std::endl; // expected output is 444
std::cout << Get<>(Data<int>{}) << std::endl; // expected output is 0
return 0;
}
Output:
444
0
Note, that size_t Get(const Data<T>& data)
is not a specialization - it is completely "different" Get()
, that is called for argument of type Data<T>
for any T
.
Here you can see working sample.
EDIT
I see you changed your question completely. However, I will still try to answer it. There is a standard workaround for lack of partial function specialization - using delegation to structs/classes.
Here is what you need:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
struct GetImpl;
template <typename T>
struct Data {
std::vector<T> data;
};
template <typename T>
struct GetImpl< Data<T> >
{
static Data<T> Get() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct GetImpl< std::vector<T> >
{
static std::vector<T> Get() {
return std::vector<T>(3);
};
};
int main() {
std::cout << GetImpl< Data<int> >::Get().data.size() << std::endl; // expected output is 2
std::cout << GetImpl< std::vector<int> >::Get().size() << std::endl; // expected output is 3
return 0;
}
Output:
2
3
Working sample can be found here.
If you don't like the syntax, you can make it a little bit shorter, by changing static function Get()
to function call operator:
template <typename T>
struct Get< Data<T> >
{
Data<T> operator()() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct Get< std::vector<T> >
{
std::vector<T> operator()() {
return std::vector<T>(3);
};
};
And then:
Get< Data<int> >()().data.size();
Get< std::vector<int> >()().size();
You have only two extra characters - ()
. This is the shortest solution I can think of.
As Columbo mentioned in his comment, you should apply the standard workaround for lack of partial specialization support for functions: delegation to a partially specialized class:
template <typename T>
struct GetImpl;
template <typename T>
T Get() { return GetImpl<T>::Do(); }
and now use partial specialization on struct GetImpl<T> { static T Do(); }
instead of Get<T>()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With