c++ - 带有 VC++ 编译器的 SFINAE

标签 c++ templates visual-c++ metaprogramming sfinae

我目前正在尝试使用 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 取得了一定的成功,但我不知道如何轻松地“修复”这段代码。

预期的结果是获取某物的调试字符串表示,如果它有 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 而不是作为返回类型:

template <class T, class = std::enable_if_t<has_getDebugString<T>::value>>
inline spString from(T v) {
    return v.getDebugString();
}

关于c++ - 带有 VC++ 编译器的 SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45332612/

相关文章:

c++ - 是否存在对类型名称有效但对基本类型无效的语言结构?

c++ - Mac 上 C++ 中 for 循环的奇怪行为

c++ - 如何检查类型是否属于给定的模板类型

c++ - 调用函数,如果有,否则忽略

c - 如何防止 Visual C 编译器优化掉 "unused"全局变量

c++ - 如果在 C++ 中超出范围,将打印出什么值

c++ - 初始化自定义类型构造函数数组

c++ - OpenGL : second VBO spoiling first VBO

c++ - 子类 B 继承自模板类 A<B>

visual-c++ - 如何向我的 C# 应用程序公开 C++ 方法?