【问题标题】:How to make SFINAE work with template specializations?如何使 SFINAE 与模板专业化一起工作?
【发布时间】:2019-06-04 13:55:40
【问题描述】:

我有一个模板方法foo。我想有几个不同的实现:Tvector<T>vector<vector<T>> 其中T 是一个内置类型或一些复杂的类。我想使用 SFINAE 来分离内置类型和类的实现,并限制一组允许的类型。

以下代码可以正常工作,但我收到警告消息:

8:37: warning: inline function 'constexpr bool isType() [with T =
 std::vector<int>]' used but never defined

8:37: warning: inline function 'constexpr bool isType() [with T =
 std::vector<std::vector<int> >]' used but never defined
#include <type_traits>
#include <vector>

using namespace std;

class ComplexClass{};

template<typename T> constexpr bool isType();
template<> constexpr bool isType<int>()  {return true;}
template<> constexpr bool isType<ComplexClass>() {return false;}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(T& value) {}

template <typename T>
inline typename enable_if<!isType<T>(), void>::type
foo(T& value) {}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(vector<T>& value) {}

template <typename T>
inline typename enable_if<isType<T>(), void>::type
foo(vector<vector<T>>& value) {}

int main()
{
    int a;
    vector<int> b;
    vector<vector<int>> c;
    ComplexClass d;
    char e;
    foo(a);
    foo(b);
    foo(c);
    foo(d);
//    foo(e); // has to lead to an error
    return 0;
}

看起来编译器试图将vector&lt;...&gt; 传递给第一个enable_if 方法但失败了。但是最好跳过这些方法,因为我们有更好的 vector&lt;T&gt;vector&lt;vector&lt;T&gt;&gt; 候选者。有可能吗?

【问题讨论】:

  • 我会选择部分专业化(并将函数放入类中)。比 SFINAE 容易得多。
  • 如果我理解正确,这是不是:wandbox.org/permlink/eRVkR4R58ezSAWhL 不是你想要的?忽略警告。

标签: c++ c++11 templates sfinae enable-if


【解决方案1】:

您似乎希望将向量重载函数模板限制为仅接受内置类型的向量。否则这些重载不需要 SFINAE。

您还可以使用std::is_fundamental 来检测内置类型:

工作示例:

using namespace std;

class ComplexClass {};

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(T& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<!is_fundamental<T>::value>::type
foo(T& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(vector<T>& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename T>
typename enable_if<is_fundamental<T>::value>::type
foo(vector<vector<T>>& value) { cout << __PRETTY_FUNCTION__ << '\n'; }

int main() {
    int a;
    vector<int> b;
    vector<vector<int>> c;
    ComplexClass d;
    char e;
    foo(a);
    foo(b);
    foo(c);
    foo(d);
    foo(e);
}

输出:

typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(T&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(std::vector<_Tp>&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(std::vector<std::vector<_Tp> >&) [with T = int; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]
typename std::enable_if<(! std::is_fundamental<_Tp>::value)>::type foo(T&) [with T = ComplexClass; typename std::enable_if<(! std::is_fundamental<_Tp>::value)>::type = void]
typename std::enable_if<std::is_fundamental<_Tp>::value>::type foo(T&) [with T = char; typename std::enable_if<std::is_fundamental<_Tp>::value>::type = void]

【讨论】:

    【解决方案2】:

    template <typename T> constexpr bool isType();
    template <> constexpr bool isType<int>()  {return true;}
    template <> constexpr bool isType<ComplexClass>() {return false;}
    

    isType&lt;char&gt; 存在,即使缺少定义。

    你可以做的是delete函数:

    template <typename T> constexpr bool isType() = delete;
    template <> constexpr bool isType<int>()  {return true;}
    template <> constexpr bool isType<ComplexClass>() {return false;}
    

    gcc/clang 没有警告:Demo

    所以foo(e); 仍然不匹配任何重载。

    我会改用标签调度:

    template <typename T> struct Tag{};
    std::true_type isType(tag<int>);
    std::false_type isType(tag<ComplexClass>);
    

    Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-27
      • 2012-10-03
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 2014-07-01
      • 1970-01-01
      相关资源
      最近更新 更多