I'd like to define a function in a template class for different cases of T. My problem is to define the case where T is a vector (whatever it contains).
Here's one of my first attempts :
template<typename T>
class Test{
protected:
T *val;
public:
Test(T* v):v(val){};
static string typeName();
};
template<typename T>
string Test<T>::typeName(){
return "other";
}
template<>
string Test<int>::typeName(){
return "int";
}
template<typename T>
string Test<vector<T>>::typeName(){
//error: invalid use of incomplete type ‘class Test<vector<T>>’
return "vector<" + Test<T>::typeName() + ">";
}
I could resolve this error by defining :
template<typename T>
class Test<vector<T>>{
// ... (the same thing)
}
but I don't want to do like this, because my class is big, and I don't want to write again the same functions. I would also like to avoid making my class inherit from another, if possible.
By searching here, I read about SFINAE but I'm a beginner with it. I tried every way I could but nothing worked. Here's another attempt :
#include <type_traits>
template<typename T,typename E=void>
class Test{
protected:
T *val;
public:
Test(T* v);
static string typeName();
static void bidon();
};
template<typename T,typename E>
string Test<T,E>::typeName(){
return "other";
}
template<>
string Test<int>::typeName(){
return "int";
}
template<typename T> struct IsVector : public std::false_type{};
template<typename T> struct IsVector<vector<T>> : public std::true_type {};
template<typename T,typename E>
string Test<T,typename std::enable_if<IsVector<T>::value,E>::type>::typeName(){
return "vector<" + Test<typename T::value_type>::typeName() + ">";
}
I had the same error. What's wrong with it ? Am I trying to do impossible things?
I think you can achieve what you want with this. The result is the same even though the approach is a little bit different.
template <typename V>
struct typeName {};
// Handle pointers
template <typename V>
struct typeName<V*> {
static string name;
};
template <typename V>
string typeName<V*>::name = typeName<V>::name + "*";
template <>
struct typeName<string> {
static string name;
};
string typeName<string>::name = "string";
template <>
struct typeName<int> {
static string name;
};
string typeName<int>::name = "int";
template <typename V>
struct typeName<vector<V>> {
static string name;
};
template <typename V>
string typeName<vector<V>>::name = "vector<" + typeName<V>::name + ">";
template <typename V>
struct typeName<set<V>> {
static string name;
};
template <typename V>
string typeName<set<V>>::name = "set<" + typeName<V>::name + ">";
int main() {
cout << typeName<vector<string>>::name << endl;
cout << typeName<set<string>>::name << endl;
cout << typeName<vector<set<string*>*>>::name;
}
stdout
vector<string>
set<string>
vector<set<string*>*>
Since your typeName method is both static and public, you can use a free helper function like this:
template< typename T > struct is_vector : std::false_type {};
template< typename... Ts > struct is_vector<vector<Ts...>> : std::true_type {};
// Standard-confirming compilers will accept the above specialization, but
// if your compiler doesn't like the above, you need to manually provide all
// template arguments to detect std::vector properly:
// template< typename T, typename Allocator >
// struct is_vector<vector<T,Allocator>> : std::true_type {};
template<typename T>
typename std::enable_if< !is_vector<T>::value, string >::type testTypeName(){
return "other";
}
template<typename T>
typename std::enable_if< is_vector<T>::value, string >::type testTypeName(){
return "vector<" + Test<typename T::value_type>::typeName() + ">";
}
template<>
string Test<int>::typeName(){
return "int";
}
template<typename T>
string Test<T>::typeName(){
return testTypeName<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