本文介绍了在VS2012的函数签名中使用enable_if和underlying_type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此代码在 VS2013 和其他编译器(已测试 clang 3.4 和 gcc 4.8)中有效,但在 VS2012 中无法编译:

This code works in VS2013 and other compilers (tested clang 3.4 and gcc 4.8) but fails to compile in VS2012:

#include <type_traits>
#include <cstdio>

// error C4519: default template arguments are only allowed on a class template

template<typename E, typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
typename std::underlying_type<E>::type to_integral(E e)
{
    return static_cast<typename std::underlying_type<E>::type>(e);
}

template<typename E, typename std::enable_if<!std::is_enum<E>::value>::type* = nullptr>
E to_integral(E e)
{
    return e;
}

enum class MyEnum : int { A = 5 };

int main()
{
    auto a = to_integral(42);
    auto b = to_integral(MyEnum::A);
    printf("%d\n", a);
    printf("%d\n", b);
}

如何在 VS2012 中编写 to_integral?是否有可能?我尝试在返回参数上使用 enable_if 并将其用作参数,但是 underlying_type 出现在函数签名中,编译器往往不喜欢非枚举类型.

How can I write to_integral in VS2012? Is it possible? I tried using enable_if on the return argument and as a parameter but then the underlying_type appears in the function signature which compilers tend not to like for non-enum types.

推荐答案

enable_if 放在返回类型中:

Put the enable_if in the return type:

template<bool b, template<class>class X, class T>
struct invoke_if {};

template<template<class>class X, class T>
struct invoke_if<true, X, T> {
  typedef typename X<T>::type type;
};

template<typename E>
typename invoke_if< std::is_enum<E>::value,std::underlying_type, E >::type
to_integral(E e) {
  return static_cast<typename std::underlying_type<E>::type>(std::move(e));
}

或者更简单的:

template<typename E>
typename std::enable_if< std::is_enum<E>::value,std::underlying_type<E> >::type::type
to_integral(E e) {
  return static_cast<typename std::underlying_type<E>::type>(std::move(e));
}

对于第一个专业.第二,我建议:

for the first specialization. For the second, I'd recommend:

template<typename E>
typename std::enable_if<!std::is_enum<E>::value&&std::is_integral<E>::value,E>::type
to_integral(E e) {
  return std::move(e);
}

应该适用于 MSVC2012 现场示例.注意额外的条件和 std::move(以防万一你有一个符合 is_integral 的 bigint 类).(通常允许在 std 中专门化这些特征).这也意味着如果你调用 to_integral(3.14) 你会得到一个错误,我认为这很好.

should work in MSVC2012 live example. Note the extra condition, and the std::move (just in case you have a bigint class that qualifies as is_integral). (it is usually allowed to specialize such traits in std). It also means that if you call to_integral(3.14) you get an error, which I think is good.

哦,还有 template 使用 enable_if_t=typename std::enable_if::type; 可以节省很多 typename 垃圾邮件(但是,2012 年要么缺乏支持,2013 年对此类事情的支持就不稳定).

Oh, and template<bool b, class T=void>using enable_if_t=typename std::enable_if<b,T>::type; can save a lot of typename spam (however, 2012 either has lack of support, and 2013 has flaky support, for this kind of thing).

这篇关于在VS2012的函数签名中使用enable_if和underlying_type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-11 01:26