我试图尽可能简单地执行SFINAE重载,以便编写几种 getSize(s) 函数:一个返回 s.getSize() ,另一个 s.GetLength() ,然后我可能会添加 s.length() 等 .

不幸的是,此代码在MSVC 2015 Update 3上产生了奇怪的错误:

我错过了什么,或者这是一些编译问题?

template <typename T> 
static size_t getSize(const T& string, decltype(&T::size) dummy = nullptr)
{
    return string.size();
}

template <typename T> 
static size_t getSize(const T& string, decltype(&T::GetLength) dummy = nullptr)
{
    return static_cast<size_t>(string.GetLength());.
}

assert(SpellCheck::getSize(CString("123")) == 3);       // .GetLength()
assert(SpellCheck::getSize(std::string("123")) == 3);   // .size()

错误C2572:'SpellCheck :: getSize':重新定义默认参数:参数1错误C2535:'size_t SpellCheck :: getSize(const T&,unknown-type)':成员函数已定义或声明错误C2672:'拼写检查: :getSize':找不到匹配的重载函数错误C2893:无法专门化函数模板'size_t SpellCheck :: getSize(const T&,unknown-type)':注意:'T = ATL :: CStringT >>'

据我所知, getSize(CString())getSize(std::string()) 至少与 dummy 指针类型不同,因此它们的签名会有所不同,重载分辨率应该可以正常工作 .

任何人都可以建议我为什么抱怨一些 unknown-type ,好吗?

我设法通过这个奇怪的结构让它工作:

template <typename T> 
static auto getSize(const T& string) -> decltype(string.size())
{ 
    return string.size(); 
}

template <typename T> 
static auto getSize(const T& string) -> decltype(static_cast<size_t>(string.GetLength()))
{ 
    return static_cast<size_t>(string.GetLength()); 
}

令人惊讶的是,使用这样的汽车它工作正常 .

我也在gcc版本7.2.0(Ubuntu 7.2.0-8ubuntu3)上检查了这个代码,两种变体都可以正常工作 . 当然,为了测试实例化,我还为gcc实现了CString:

#ifdef _WIN32
#include <atlstr.h>
#else
struct CString
{
    CString(const char*)  {}
    int GetLength() const { return 3; }.
};
#endif

那么,请建议我,我是否遗漏了某些内容或第一个示例触发了一些特定于MS的问题?

编辑:简化的第二个解决方案