2

起初我使用 enable_if ,我在下面写的代码不会编译,但它在逻辑上似乎是正确的,但不会被当前的 enable_if 实现支持。

  1 
  2 #include <iostream>
  3 using namespace std;
  4 
  5 template<int N>
  6 struct S{
  7                 template<class T>
  8                 typename enable_if<N==1,T>::type
  9                 f(T t) {return 1;};
 10 
 11                 template<class T>
 12                 T
 13                 f(T t) {return 0;};
 14 };
 15 
 16 int main() {
 17     S<1> s1;
 18     S<2> s2;
 19     cout << s1.f(99) <<" "<< s2.f(99) << endl;
 20     return 0;
 21 }

错误信息准确,问题准确指出。

enable_if.cc19:20: error: call of overloaded ‘f(int)’ is ambiguous
enable_if.cc:9:3: error: no type named ‘type’ in   
                         ‘struct std::enable_if<false, int>’

这似乎只是设计不明确的问题,很容易纠正。为了处理它,我可以编写部分专门的类模板:

#include <iostream>
using namespace std;

template<int N> struct S{
        template<class T>
        T
        f(T t) {return 0;};
};
template<> struct S<1>{
        template<class T>
        T
        f(T t) {return 1;};
};
int main() {
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) <<" "<< s2.f(99) << endl;
    return 0;
}

但是为了清洁和方便,首先要增强 enable_if 模板以支持错误代码催生的这些新功能呢?

  • 调用 f时s1,可以使用例子中返回 1 的更专业的那个。
  • 调用 f时s2,将使用返回 0 的通用函数,即使第一个失败。
4

4 回答 4

2

您可以通过以下方式解决该问题:

  1. 在您的函数模板上放置互斥的 SFINAE 约束;
  2. enable_if强制在调用时执行评估。

例如:

#include <type_traits>

template<int N>
struct S
{
    template <class T>
    typename std::enable_if<N == 1 && std::is_same<T, T>::value, int>::type
    f(T t) {return 1;}

    template <class T>
    typename std::enable_if<N != 1, T>::type
    f(T t) {return 0;}
};

这是一个活生生的例子

于 2013-06-12T08:33:12.803 回答
1

首先,我怀疑您的代码中有错字。启用 if 应该在 T 上参数化,以编译:typename enable_if<N==1,T>::type而不是typename enable_if<N==1,int>::type

只需将第二个重载与 enable if 一起使用,也可以使用反转条件。有用:

#include <iostream>

using namespace std;

template<int N>
struct S{
                template<class T>
                typename enable_if<N==1,T>::type
                f(T t) {return 1;};

                template<class T>
                typename enable_if<N!=1,T>::type
                f(T t) {return 0;};
};

int main() {
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) <<" "<< s2.f(99) << endl;
    return 0;
}
于 2013-06-12T08:37:15.947 回答
0

你仍然可以在没有部分专业化的情况下做到这一点,但是:

  1. 您必须确保只有其中一个功能存在(否则会产生歧义)

  2. 您必须使enable_if条件依赖于模板参数。

这有效:

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


template <int N>
struct S
{
    template <typename T>
    typename enable_if<(sizeof(T)>0) && N==1, int>::type
    f(T t) { return 1; }

    template <typename T>
    typename enable_if<(sizeof(T)>0) && N!=1, T>::type
    f(T t) { return 0; }
};

int main()
{
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) << " " << s2.f(99) << endl;
}

活生生的例子

于 2013-06-12T08:33:05.093 回答
0

std::enable_if只是一个选择函数重载的工具。它被实现为来自boost的纯库解决方案。我认为选择正确的重载规则并不容易。但是,在某些情况下要求在enable_if涉及的情况下改变这一点会使事情变得更加复杂。所以你最好使用部分专业化和析取enable_if

于 2013-06-12T09:00:32.007 回答