3

我想在模板类中为 T 的不同情况定义一个函数。我的问题是定义 T 是向量的情况(无论它包含什么)。

这是我的第一次尝试:

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() + ">";
}

我可以通过定义来解决这个错误:

template<typename T>
class Test<vector<T>>{
    // ... (the same thing)
}

但我不想这样做,因为我的班级很大,我不想再次编写相同的函数。如果可能的话,我还想避免让我的类从另一个类继承。

通过在这里搜索,我了解了 SFINAE,但我是它的初学者。我尝试了所有可能的方法,但没有任何效果。这是另一个尝试:

#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() + ">";
}

我有同样的错误。它出什么问题了 ?我在尝试做不可能的事情吗?

4

4 回答 4

3

由于您的typeName方法是staticand public,您可以使用这样的免费辅助函数:

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>();
}
于 2013-04-16T16:36:05.913 回答
3

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*>*>
于 2013-04-16T16:30:12.940 回答
1

您可以制作一个单独的模板,其中包含该函数,并让主模板调用辅助模板的函数:

template <typename T>
struct tn_helper {
    static string typeName(){
        return "other";
    }
};

template <typename T>
string Test::typeName(){
    return tn_helper<T>::typeName();;
}

template<>
struct tn_helper<int> {
    static string typeName(){
        return "int";
    }
};

template<typename T>
struct tn_helper<vector<T> > {
    static string typeName(){
        return "vector<" + tn_helper<T>::typeName() + ">";
    }
};

// etc.
于 2013-04-16T16:35:06.120 回答
1

我不知道为什么您最初的尝试不起作用(就像您希望它编译一样,希望其他人可以对此有所了解)但作为一种解决方法,您可以制作一个单独的模板类,其中仅包含您的静态函数,并在您的主类中使用该类。类似于以下内容:

template<typename T>
struct TypeName {
    static std::string typeName() { return "other"; }
};
template<>
struct TypeName<int> {
    static std::string typeName() { return "int"; }
};
template<typename T>
struct TypeName<std::vector<T>> {
    static std::string typeName() { return "vector<" + TypeName<T>::typeName() + ">"; }
};

template<typename T>
class Test {
public:
    static std::string typeName() { return TypeName<T>::typeName(); }
    // more stuff
};
于 2013-04-16T16:35:18.987 回答