繁体   English   中英

使用std :: enable_if和std :: is_arithmetic作为模板参数进行故障

[英]Troubles with std::enable_if and std::is_arithmetic as template parameter

我正在尝试实现一个OutputArchive模板类,它具有模板化函数processImpl() 看起来像这样:

template<typename ArchiveType>
class OutputArchive {
    ...

    template<typename Type, typename std::enable_if_t<std::is_arithmetic_v<Type>>> inline
    ArchiveType& processImpl(Type&& type) {
        // Implementation
    }

    template<typename Type, typename = void> inline
    ArchiveType& processImpl(Type&& type) {
        // Implementation
    }
}

这里的想法是,如果我将一个charintfloat等传递给我的processImpl()函数,应该使用第一个重载; 然而,事实并非如此。 第二次重载似乎总是被使用,我完全不知道我可能做错了什么。 我想它确实与我使用std::enable_if

所以要使它工作,你应该使用std :: enable_if 2个案例。 我将展示返回类型的示例,但使用模板参数也可以。

template<typename Type> inline
typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
    // Implementation
}

template<typename Type> inline
typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&> processImpl(Type&& type) {
    // Implementation
}

请注意第二种情况中的否定。

但是从C ++ 17开始,更好的方法是使用constexpr:

ArchiveType& processImpl(Type&& type) {
    if constexpr(std::is_arithmetic_v<type>) {
        // implementation
    } else {
        // implementation
    }
}

您的代码中存在一些问题。

没有特别的顺序

1)不是错误(我猜)但是......使用typename std::enable_if<...>::type或者从C ++ 14开始, std::enable_if_t<...> ; std::enable_if_t之前不需要使用typename

2)如果你想在参数类型列表中使用std::enable_if ,这个不起作用

 template <typename T, std::enable_if_t<(test with T)>>

因为,如果用T测试是真的,就变成了

 template <typename T, void>

作为模板函数的签名没有意义。

您可以SFINAE启用/禁用返回值(请参阅Igor或Marek R的答案)或者您可以编写,而不是

 template <typename T, std::enable_if_t<(test with T)> * = nullptr>

成为

 template <typename T, void * = nullptr>

并且有意义,作为签名,并且有效

3)如注释中所指出的,你应该使用std::remove_reference ,所以

   template <typename Type,
             std::enable_if_t<std::is_arithmetic_v<
                std::remove_reference_t<Type>>> * = nullptr> inline
   ArchiveType & processImpl (Type && type)

现在这个函数应该拦截算术值,但......

4)前面的processImpl() ,对于算术值,与其他processImpl()冲突,因为在算术值的情况下,两个版本都匹配,编译器不能选择另一个。

我可以建议两种解决方案

(a)通过SFINAE禁用算术案例中的第二个版本; 我的意思是,写下第二个如下

   template <typename Type,
             std::enable_if_t<false == std::is_arithmetic_v<
                std::remove_reference_t<Type>>> * = nullptr> inline
    ArchiveType & processImpl (Type && type)

(b)中通过该发送的附加的中间函数int值和接收int在算术版本和一个long的通用的; 我的意思是

   template <typename Type,
             std::enable_if_t<std::is_arithmetic_v<
                  std::remove_reference_t<Type>>> * = nullptr> inline
   ArchiveType & processImpl (Type && type, int)
    { /* ... */ }

   template <typename Type>
   ArchiveType & processImpl (Type && type, long)
    { /* ... */ }

   template <typename Type>
   ArchiveType & processImpl (Type && type)
    { return processImpl(type, 0); }

这样,算法版本(完全接收int )优先于通用版本(在启用时); 否则使用通用版本。

以下是基于(b)解决方案的完整工作C ++ 14示例

#include <iostream>
#include <type_traits>

template <typename ArchiveType>
struct OutputArchive
 {
   ArchiveType  value {};

   template <typename Type,
             std::enable_if_t<std::is_arithmetic_v<
                std::remove_reference_t<Type>>> * = nullptr> inline
   ArchiveType & processImpl (Type && type, int)
    {
      std::cout << "--- processImpl aritmetic: " << type << std::endl;

      return value;
    }

   template <typename Type>
   ArchiveType & processImpl (Type && type, long)
    {
      std::cout << "--- processImpl generic: " << type << std::endl;

      return value;
    }

   template <typename Type>
   ArchiveType & processImpl (Type && type)
    { return processImpl(type, 0); }
 };

int main()
 {
   OutputArchive<int>  oa;

   long  l{2l};
   oa.processImpl(l);
   oa.processImpl(3);
   oa.processImpl("abc");
 }

这应该可以解决问题

template<typename ArchiveType>
class OutputArchive {
    ...
    template<typename Type>
    inline
    typename std::enable_if_t<std::is_arithmetic_v<Type>, ArchiveType&>
    processImpl(Type type) {
        // Implementation
    }

    template<typename Type>
    inline
    typename std::enable_if_t<!std::is_arithmetic_v<Type>, ArchiveType&>
    processImpl(Type&& type) {
        // Implementation
    }
};

现场样本

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM