C ++ enable_if_t SFINAE

时间:2017-10-18 18:08:47

标签: c++ templates

我试图理解为什么这段代码没有按预期工作

#include <cstdio>
#include <vector>
#include <type_traits>
using namespace std;

struct Foo {

};

template<typename T, typename = void>
void compare(const T&a, const T&b) {
    cout << "default" << endl;
}

template<typename T, std::enable_if_t<std::is_same<T, Foo>::value>>
void compare(const T& a, const T &b) {
    cout << "In object" << endl;
}

int main(int argc, char const *argv[]) {
    compare(1, 2);

    {
        vector<int> a, b;
        compare(a, b);
    }

    {
        Foo a, b;
        compare(a, b);
    }

    return 0;
}

在所有情况下都会打印“默认”。对于最后一种情况,我希望调用第二个函数。

3 个答案:

答案 0 :(得分:3)

你没有专门化inline static int counter{1}; (无论如何都不可能部分地专门化一个功能模板)。而是提供过载。

超载总是非法的:

  1. 未定义compare
  2. 或者它指定类型为enable_if_t的非类型模板参数。
  3. 所以它永远不会被调用,因为SFINAE放弃了它而支持顶部始终有效的过载。

    专业化通常是功能模板的错误答案。相反,你应该委托一个类模板,在真正的专业化时按预期行事:

    void

答案 1 :(得分:2)

使用类模板是一种有效的解决方案,这是通过标记调度实现此结果的另一种方法:

    template <class T>
    void compare(const T & l, const T & r, std::true_type)
    {
      cout << "In object" << endl;
    }

    template <class T>
    void compare(const T & l, const T & r, std::false_type)
    {
      cout << "default" << endl;
    }

    template <class T>
    void compare(const T & l, const T & r)
    {
      compare(l, r, std::is_same<T, Foo>{});
    }

答案 2 :(得分:1)

推迟使用专门的函数对象可以在参数类型和/或它们是rvalues还是lvalues方面提供很大的灵活性。

#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;


// general case
template<class T> 
struct compare_impl
{
    template<class U, class V>
    auto operator()(U&& a, V&& b) const {
        cout << "default" << endl;
    }
};

// compare interface
template<class T, class U>
auto compare(T && a, U && b)
{
    using ctype = std::common_type_t<std::decay_t<T>, std::decay_t<U>>;
    auto impl = compare_impl<ctype>();
    return impl(a, b);
}


// now specialise for objects for which we want custom behaviour
struct Foo {

};

template<>
struct compare_impl<Foo>
{
    template<class U, class V>
    auto operator()(U&& a, V&& b) const {
        cout << "In object" << endl;
    }
};


int main(int argc, char const *argv[]) {

    compare(1, 2);

    {
        vector<int> a, b;
        compare(a, b);
    }

    {
        Foo a, b;
        compare(a, b);
    }

    return 0;
}