SFINAE decltype逗号运算符技巧

SFINAE decltype comma operator trick

本文关键字:运算符 decltype SFINAE      更新时间:2023-10-16

在阅读了Matthieu在这里的回答后,我决定自己尝试一下。

我的尝试编译失败,因为SFINAE没有启动并剔除尝试访问T::foohas_foo函数。

error: ‘struct Bar’ has no member named ‘foo’

我是错过了什么,还是我试图以这种方式做的事情不可能?

(我使用的是gcc-4.7.2)

完整示例如下:

#include <iostream>
// culled by SFINAE if foo does not exist
template<typename T>
constexpr auto has_foo(T& t) -> decltype((void)t.foo, bool())
{
    return true;
}
// catch-all fallback for items with no foo
constexpr bool has_foo(...)
{
    return false;
}
//-----------------------------------------------------
template<typename T, bool>
struct GetFoo
{
    static int value(T& t)
    {
        return t.foo;
    }
};
template<typename T>
struct GetFoo<T, false>
{
    static int value(T&)
    {
        return 0;
    }
};
//-----------------------------------------------------
template<typename T>
int get_foo(T& t)
{
    return GetFoo<T, has_foo(t)>::value(t);
}
//-----------------------------------------------------
struct Bar
{
    int val;
};
int main()
{
    Bar b { 5 };
    std::cout << get_foo(b) << std::endl;
    return 0;
}

AFAICS的主要问题是使用运行时引用作为constexpr函数参数。更换这个效果很好。

#include <iostream>
// culled by SFINAE if foo does not exist
template<typename T>
constexpr auto has_foo(int) -> decltype(std::declval<T>().foo, bool())
{
    return true;
}
// catch-all fallback for items with no foo
template<typename T> constexpr bool has_foo(...)
{
    return false;
}
//-----------------------------------------------------
template<typename T, bool>
struct GetFoo
{
    static int value(T& t)
    {
        return t.foo;
    }
};
template<typename T>
struct GetFoo<T, false>
{
    static int value(T&)
    {
        return 0;
    }
};
//-----------------------------------------------------
template<typename T>
int get_foo(T& t)
{
    return GetFoo<T, has_foo<T>(0)>::value(t);
}
//-----------------------------------------------------
struct Bar
{
    int val;
};
struct Foo {
    int foo;
};
int main()
{
    Bar b { 5 };
    Foo f { 5 };
    std::cout << get_foo(b) << std::endl;
    std::cout << get_foo(f) << std::endl;
    return 0;
}