C++ 通过类模板参数跨平台选择运算符重载

C++ 通过类模板参数跨平台选择运算符重载,c++,templates,gcc,visual-studio-2015,clang,C++,Templates,Gcc,Visual Studio 2015,Clang,我正在尝试编写一个模板类,它本质上只是其他类型的包装器,以便能够轻松地监视值发生的事情——每次调用任何运算符、构造函数、析构函数等。 因此,我试图通过对任何有操作符bool()的类调用操作符bool()来生成一个操作符bool(),对任何没有操作符bool()的类调用static_cast。如果有人试图转换为bool,则不能执行这两项操作的类只能在编译失败。我还没有把重点放在这一部分,因为我被这个简单的案例难住了 它在MSVC 2015上编译并运行良好,但不会在Clang(3.8.1)或GCC(

我正在尝试编写一个模板类,它本质上只是其他类型的包装器,以便能够轻松地监视值发生的事情——每次调用任何运算符、构造函数、析构函数等。 因此,我试图通过对任何有操作符bool()的类调用操作符bool()来生成一个操作符bool(),对任何没有操作符bool()的类调用static_cast。如果有人试图转换为bool,则不能执行这两项操作的类只能在编译失败。我还没有把重点放在这一部分,因为我被这个简单的案例难住了

它在MSVC 2015上编译并运行良好,但不会在Clang(3.8.1)或GCC(6.2)上编译。GCC和Clang都设置为
-std=c++1z

链接到在线编译器,显示GCC和Clang上的错误:

这是一个显示问题的精简版本:

#include <type_traits>
#include <utility>
#include <assert.h>

template <typename T>
struct Wrapper {
    T val;

    template<typename...Params>
    Wrapper(Params&&...args): val(std::forward<Params>(args)...){}

    /**
    * \brief bool conversion operator
    */
    template <typename = std::enable_if_t<std::is_fundamental<T>::value>>
    operator bool() const {
        return static_cast<bool>(val);
    }

    /**
    * \brief bool conversion operator
    */
    template <typename = std::enable_if_t<!std::is_fundamental<T>::value>, typename = void>
    operator bool() const {
        return val.operator bool();
    }
};


struct HasOperatorBool {
    mutable bool done{ false };

    operator bool() const{
        done = true;
        return done;
    }
};

int main(int argc, char** argv) {
    Wrapper<HasOperatorBool> whob;
    bool didIt = whob;
    assert(didIt);

    Wrapper<int> wi{1};
    bool bi = wi;
    assert(bi);

    return 0;
}
叮当声:

In file included from /tmp/gcc-explorer-compiler116910-70-1nlkefa/example.cpp:1:0:
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::is_fundamental<HasOperatorBool>::value; _Tp = void]':
16 : required from 'struct Wrapper<HasOperatorBool>'
40 : required from here
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/type_traits:2512:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
包含在/tmp/gcc-explorer-compiler116910-70-1nlkefa/example.cpp:1:0:
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/type_traits:替换“使用enable_if_t=typename std::enable_if::type[with bool _Cond=std::is_basical::value;_Tp=void]的模板”:
16:从“结构包装器”中需要
40:从这里开始需要
/opt/gcc explorer/gcc-6.2.0/include/c++/6.2.0/type_traits:2512:61:错误:在“struct std::enable_if”中没有名为“type”的类型
使用enable_if_t=typename enable_if::type;

我可能对替代方法感兴趣,但我对为什么这三个编译器中的两个无法使用的技术原因非常感兴趣。是否有一个或多个编译器出错?有什么方法可以实现我想要的吗?

你实际上没有在做SFINAE。当使用
std::enable_if
时,所讨论的
T
应该直接来自编译器试图实例化的模板(the)。但是由于
T
是类的模板参数,而不是方法,因此替换失败,并给出一个硬错误,而不是SFINAE。我不确定VS的行为是否符合这方面的标准

相反,您需要引入一个默认为类模板参数的伪模板参数:

/**
* \brief bool conversion operator
*/
template <typename X = T, typename = std::enable_if_t<std::is_fundamental<X>::value>>
operator bool() const {
    return static_cast<bool>(val);
}

/**
* \brief bool conversion operator
*/
template <typename X = T, typename = std::enable_if_t<!std::is_fundamental<X>::value>, typename = void>
operator bool() const {
    return val.operator bool();
}
/**
*\brief布尔转换运算符
*/
模板
运算符bool()常量{
返回静态_-cast(val);
}
/**
*\brief布尔转换运算符
*/
模板,typename=void>
运算符bool()常量{
返回val.operator bool();
}

谢谢,回答得很好!编译器资源管理器页面在编译时以彩色显示的方式是如此令人兴奋!当然,它在intellisense中仍然不起作用,但这并不是什么大问题:P(intellisense认为它模棱两可)
/**
* \brief bool conversion operator
*/
template <typename X = T, typename = std::enable_if_t<std::is_fundamental<X>::value>>
operator bool() const {
    return static_cast<bool>(val);
}

/**
* \brief bool conversion operator
*/
template <typename X = T, typename = std::enable_if_t<!std::is_fundamental<X>::value>, typename = void>
operator bool() const {
    return val.operator bool();
}