带有 VC++ 编译器的 SFINAE
SFINAE with VC++ compiler
我目前正在尝试使用 VC++ 编译器编译一个简单的 SFINAE 结构。我的版本(根据 cl 命令)是
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
此代码在 clang 上编译良好
// Example program
#include <iostream>
#include <string>
#include <typeinfo>
struct spString
{
template <class... T>
spString format(T...) { return spString(); }
const char* c_str() { return nullptr; }
spString operator+(spString) { return spString(); }
spString operator+(const char*) { return spString(); }
};
struct debuggable
{
spString getDebugString() { return spString(); }
};
void fromFloat(spString, float&) {}
void fromInt(spString, int&) {}
template <class T> inline auto from( T v )
-> decltype( v.getDebugString(), spString() )
{
return v.getDebugString();
}
template <class T> inline auto from( T v )
-> decltype( v->getDebugString(), spString() )
{
spString r;
r.format( "%u (%s)", (size_t) v, v->getDebugString().c_str() );
return r;
}
template <class T> inline spString from( T v )
{
return spString("(") + typeid(T).name() + " instance)";
}
template <> inline spString from( float _v ) { spString _d; fromFloat ( _d, _v ); return _d; }
template <> inline spString from( int _v ) { spString _d; fromInt ( _d, _v ); return _d; }
//other base types
int main()
{
debuggable x{};
from(0);
from(0.f);
from(x);
}
但在 Microsoft 的编译器上会失败。不,我不能使用其他版本,我只能使用我现在正在使用的版本。我总是在这个编译器上使用 SFINAE 减轻了成功,但我不知道如何轻松 "fix" 这段代码。
预期的结果是获取某物的调试字符串表示,如果它有 getDebugString,则使用此方法,如果它是基类型,则使用自定义方法,否则,仅打印类型的名称。
你认为我的 visual studio 版本有什么方法可以实现这一目标吗?
这里是做你想做的事情的方法 - 用 VC 19.00.24215.1.
测试
检测到帮助模板 getDebugString()
:
template <typename T>
auto has_getDebugString_impl(int) ->
decltype(void(std::declval<T>().getDebugString()), std::true_type{});
template <typename T>
auto has_getDebugString_impl(...) -> std::false_type;
template <typename T>
struct has_getDebugString: decltype(has_getDebugString_impl<T>(0)) { };
结合std::enable_if
:
template <class T>
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T v) {
return v.getDebugString();
}
template <class T>
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T *v) {
spString r;
r.format("%u (%s)", (size_t)v, v->getDebugString().c_str());
return r;
}
template <class T>
inline std::enable_if_t < ! has_getDebugString<T>::value, spString > from(T v) {
return spString("(") + typeid(T).name() + " instance)";
}
并为特定类型重载(非专用模板):
inline spString from(float _v) { spString _d; fromFloat(_d, _v); return _d; }
inline spString from(int _v) { spString _d; fromInt(_d, _v); return _d; }
这不是最漂亮的代码,可能还有更直接的方法,但我不得不在 VC 中处理一些问题...
注意: 如果需要,您可以在默认模板参数中使用 enable_if
而不是 return 类型:
template <class T, class = std::enable_if_t<has_getDebugString<T>::value>>
inline spString from(T v) {
return v.getDebugString();
}
我目前正在尝试使用 VC++ 编译器编译一个简单的 SFINAE 结构。我的版本(根据 cl 命令)是
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
此代码在 clang 上编译良好
// Example program
#include <iostream>
#include <string>
#include <typeinfo>
struct spString
{
template <class... T>
spString format(T...) { return spString(); }
const char* c_str() { return nullptr; }
spString operator+(spString) { return spString(); }
spString operator+(const char*) { return spString(); }
};
struct debuggable
{
spString getDebugString() { return spString(); }
};
void fromFloat(spString, float&) {}
void fromInt(spString, int&) {}
template <class T> inline auto from( T v )
-> decltype( v.getDebugString(), spString() )
{
return v.getDebugString();
}
template <class T> inline auto from( T v )
-> decltype( v->getDebugString(), spString() )
{
spString r;
r.format( "%u (%s)", (size_t) v, v->getDebugString().c_str() );
return r;
}
template <class T> inline spString from( T v )
{
return spString("(") + typeid(T).name() + " instance)";
}
template <> inline spString from( float _v ) { spString _d; fromFloat ( _d, _v ); return _d; }
template <> inline spString from( int _v ) { spString _d; fromInt ( _d, _v ); return _d; }
//other base types
int main()
{
debuggable x{};
from(0);
from(0.f);
from(x);
}
但在 Microsoft 的编译器上会失败。不,我不能使用其他版本,我只能使用我现在正在使用的版本。我总是在这个编译器上使用 SFINAE 减轻了成功,但我不知道如何轻松 "fix" 这段代码。
预期的结果是获取某物的调试字符串表示,如果它有 getDebugString,则使用此方法,如果它是基类型,则使用自定义方法,否则,仅打印类型的名称。
你认为我的 visual studio 版本有什么方法可以实现这一目标吗?
这里是做你想做的事情的方法 - 用 VC 19.00.24215.1.
测试检测到帮助模板 getDebugString()
:
template <typename T>
auto has_getDebugString_impl(int) ->
decltype(void(std::declval<T>().getDebugString()), std::true_type{});
template <typename T>
auto has_getDebugString_impl(...) -> std::false_type;
template <typename T>
struct has_getDebugString: decltype(has_getDebugString_impl<T>(0)) { };
结合std::enable_if
:
template <class T>
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T v) {
return v.getDebugString();
}
template <class T>
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T *v) {
spString r;
r.format("%u (%s)", (size_t)v, v->getDebugString().c_str());
return r;
}
template <class T>
inline std::enable_if_t < ! has_getDebugString<T>::value, spString > from(T v) {
return spString("(") + typeid(T).name() + " instance)";
}
并为特定类型重载(非专用模板):
inline spString from(float _v) { spString _d; fromFloat(_d, _v); return _d; }
inline spString from(int _v) { spString _d; fromInt(_d, _v); return _d; }
这不是最漂亮的代码,可能还有更直接的方法,但我不得不在 VC 中处理一些问题...
注意: 如果需要,您可以在默认模板参数中使用 enable_if
而不是 return 类型:
template <class T, class = std::enable_if_t<has_getDebugString<T>::value>>
inline spString from(T v) {
return v.getDebugString();
}