首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::enable_if和std::is_arithmetic作为模板参数的故障

std::enable_if和std::is_arithmetic作为模板参数的故障
EN

Stack Overflow用户
提问于 2018-10-13 21:41:14
回答 3查看 3.4K关注 0票数 5

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

代码语言:javascript
复制
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的方式有关

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-10-13 22:33:47

因此,为了使它工作,您应该使用std::enable_if的2种情况。我将给出一个返回类型的示例,但是使用模板参数也可以。

代码语言:javascript
复制
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:

代码语言:javascript
复制
ArchiveType& processImpl(Type&& type) {
    if constexpr(std::is_arithmetic_v<type>) {
        // implementation
    } else {
        // implementation
    }
}
票数 6
EN

Stack Overflow用户

发布于 2018-10-13 22:55:52

您的代码中有一些问题。

没有特别的顺序

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

2)如果要在参数类型列表中使用std::enable_if,则此类型不能工作

代码语言:javascript
复制
 template <typename T, std::enable_if_t<(test with T)>>

因为,如果使用T进行的测试为真,则

代码语言:javascript
复制
 template <typename T, void>

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

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

代码语言:javascript
复制
 template <typename T, std::enable_if_t<(test with T)> * = nullptr>

变成

代码语言:javascript
复制
 template <typename T, void * = nullptr>

和有意义的,作为签名,和工作

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

代码语言:javascript
复制
   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禁用算术情况下的第二个版本;我的意思是,将第二个版本写成如下

代码语言:javascript
复制
   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;我的意思是

代码语言:javascript
复制
   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示例

代码语言:javascript
复制
#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");
 }
票数 6
EN

Stack Overflow用户

发布于 2018-10-13 22:41:45

这应该能起作用

代码语言:javascript
复制
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
    }
};

活样品

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52797598

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档