为什么SFINAE不适用于此示例?

时间:2016-06-10 10:41:45

标签: c++ c++14 sfinae

我希望通过应用SFINAE来编译以下最小的例子:

#include <iostream>
#include <string>
#include <type_traits>

struct FallBack{};

struct S {
    int bar() { return 42; }
};

template <typename A, typename B>
std::enable_if_t< (std::is_same< std::enable_if_t<true==FLAG, FallBack>, FallBack>::value and std::is_convertible<B, std::string>::value), int >
    foo ( A a) { return a.bar();
}


template <typename A, typename B>
std::enable_if_t<false==FLAG, int>
foo ( A a) { std::cout << "false solution " << std::endl; return -1; }



int main()
{
    std::cout << foo<S, std::string>( S{}) << std::endl;
}

编译它: g++ -std=c++14 -DFLAG=1 myFile.cc

如果我评论第二个foo功能,一切正常,因此我对SFINAE的理解不正确;此外,编译器抱怨foo的定义含糊不清。

我显然是错的,但看不出问题。 可以请任何人评论和解释为什么SFINAE不适用?

3 个答案:

答案 0 :(得分:3)

您具有非模板相关条件。

您应该执行类似

的操作
template <typename A, typename B>
std::enable_if_t<std::is_same<A, A>::value == FLAG, int>
foo (A a) { std::cout << "false solution " << std::endl; return -1; }

答案 1 :(得分:2)

为什么不使用:

#if FLAG == 1
template <typename A, typename B>
std::enable_if_t<std::is_convertible<B, std::string>::value, int >
    foo ( A a) { return a.bar();
}
#else
template <typename A, typename B>
int foo ( A a) { std::cout << "false solution " << std::endl; return -1; }
#endif

鉴于您无论如何都使用了编译时定义,使用它来明确指定您需要的定义而不是完全依赖SFINAE是有意义的。

答案 2 :(得分:1)

正如@ Jarod42所说,sfinae表达式不适用于非模板相关条件。

无论如何,如果你可以将它分成两个结构,这里有一个解决方案:

#include <iostream>
#include <string>
#include <type_traits>

struct S {
    int bar() { return 42; }
};

template <typename B, bool = FLAG>
struct T {
    template<typename A>
    static void foo ( A a ) {
        static_assert(std::is_convertible<B, std::string>::value, "!");
        std::cout << a.bar() << std::endl;
    }
};

template <typename B>
struct T<B, false> {
    template<typename A>
    static void foo( A a ) {
        static_assert(std::is_convertible<B, std::string>::value, "!");
        std::cout << "false solution " << std::endl;
    }
};

int main() {
    T<std::string>::foo(S{});
    T<std::string, true>::foo(S{});
    T<std::string, false>::foo(S{});
}

它基于部分专业而不是sfinae 此解决方案的缺点(或者是功能?)是您仍然可以通过明确强制FLAG参数来解决bool的问题。 有关详细信息,请参阅上面的代码。