我的以下代码应检测T
是否具有begin
和end
方法:
template <typename T>
struct is_container
{
template <typename U, typename U::const_iterator (U::*)() const,
typename U::const_iterator (U::*)() const>
struct sfinae {};
template <typename U> static char test(sfinae<U, &U::begin, &U::end>*);
template <typename U> static long test(...);
enum { value = (1 == sizeof test<T>(0)) };
};
这是一些测试代码:
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <map>
int main()
{
std::cout << is_container<std::vector<std::string> >::value << ' ';
std::cout << is_container<std::list<std::string> >::value << ' ';
std::cout << is_container<std::set<std::string> >::value << ' ';
std::cout << is_container<std::map<std::string, std::string> >::value << '\n';
}
在g++ 4.5.1上,输出为
1 1 1 1
。但是,在Visual Studio 2008上,输出为1 1 0 0
。我做错了什么,还是仅仅是VS 2008错误?任何人都可以在其他编译器上进行测试吗?谢谢! 最佳答案
因此,这就是我调试这些东西的方法。
首先,注释掉否定的替代方案,以使您得到一个错误,而不仅仅是不匹配。
接下来,尝试使用不起作用的项之一实例化要在函数中放入的类型。
在这一步,我可以实例化您的sfinae对象,但是它仍然无法正常工作。 “这让我知道这是一个VS错误,因此问题是如何解决它。” -OBS
按照您的方式做,VS似乎在SFINAE上遇到了麻烦。当然可以!当您包裹sfinae对象时,它会更好地工作。我这样做是这样的:
template <typename U, typename it_t = typename U::const_iterator >
struct sfinae
{
// typedef typename U::const_iterator it_t; - fails to compile with non-cont types. Not sfinae
template < typename U, typename IT, IT (U::*)() const, IT (U::*)() const >
struct type_ {};
typedef type_<U,it_t,&U::begin,&U::end> type;
};
仍然无法正常工作,但至少我收到了一条有用的错误消息:
error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::_Tree_const_iterator<_Mytree> (__thiscall std::set<_Kty>::* )(void) const'
这让我知道
&U::end
不足以使VS(任何编译器)知道我想要哪一个end()。 static_cast修复了: typedef type_<U,it_t,static_cast<it_t (U::*)() const>(&U::begin),static_cast<it_t (U::*)() const>(&U::end)> type;
将它们放在一起,并在其上运行测试程序... VS2010成功。您可能会发现static_cast实际上是您所需要的,但是我留给您了解。
我想现在的真正问题是,哪个编译器正确?我的赌注是一致的:g++。指向明智的人:永远不要假设我当时所做的。
编辑:耶什...你错了!
更正的版本:
template <typename T>
struct is_container
{
template <typename U, typename it_t = typename U::const_iterator >
struct sfinae
{
//typedef typename U::const_iterator it_t;
template < typename U, typename IT, IT (U::*)() const, IT (U::*)() const >
struct type_ {};
typedef type_<U,it_t,static_cast<it_t (U::*)() const>(&U::begin),static_cast<it_t (U::*)() const>(&U::end)> type;
};
template <typename U> static char test(typename sfinae<U>::type*);
template <typename U> static long test(...);
enum { value = (1 == sizeof test<T>(0)) };
};
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <map>
int main()
{
std::cout << is_container<std::vector<std::string> >::value << ' ';
std::cout << is_container<std::list<std::string> >::value << ' ';
std::cout << is_container<std::set<std::string> >::value << ' ';
std::cout << is_container<std::map<std::string, std::string> >::value << ' ';
std::cout << is_container<bool>::value << '\n';
}
--
上面的调试是明智的,但是关于编译器的假设是错误的。由于我上面强调的原因,G++应该失败了。