【问题标题】:Visual studio - workaround error c2770 on std::enable_ifVisual Studio - std::enable_if 上的解决方法错误 c2770
【发布时间】:2015-07-13 19:07:04
【问题描述】:

从这里得到答案:iterate over tuple 关于打印std::tuple 组件,这里是代码:

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I == sizeof...(Tp), void>::type
print(const std::tuple<Tp...>& t)
{ }

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I < sizeof...(Tp), void>::type
    print(const std::tuple<Tp...>& t)
{
    std::cout << std::get<I>(t) << std::endl;
    print <i, Tp...> (t);
}

这可以在 GCC 上完美编译和运行,但无法在 VC++ 上编译(我使用 Visual Studio 2013)。我得到的错误:

Error   4   error C2893: Failed to specialize function template 'std::enable_if<I==1,void>::type print(const std::tuple<_Types1...> &)' 
Error   3   error C2770: invalid explicit template argument(s) for 'std::enable_if<I<1,void>::type print(const std::tuple<_Types1...> &)'   

显然,当使用带有显式模板参数的std::enable_if 时,C2770 上有一个已记录的错误。一些开发人员建议使用const int 作为模板的预参数

const int i = I+1;
print<i,Tp...>(t);

但这也不起作用。 还有其他解决方案,例如使用一些宏,但它们也失败了。
有人可以解决它吗?我搜索了一个解决方案,但没有找到真正有效的解决方案。
谢谢。

【问题讨论】:

  • 在 VS2015 RC 中为我工作。发布(希望)很快,因此工具链升级可能是非标准的,但也是可行的选择。 (VS2015更不用说constexpr,更快的编译和链接等)
  • 感谢他们修复了它 :)

标签: c++ c++11 visual-studio-2012 visual-c++ visual-studio-2013


【解决方案1】:

您可以使用以下方法之一:

  • 使用递减递归和(部分)特化:

    namespace detail
    {
        template <std::size_t N>
        struct printer
        {
            template <typename TUPLE>
            void operator () (const TUPLE& t) const
            {
                printer<N - 1>{}(t);
                std::cout << std::get<N - 1>(t) << std::endl;
            }
        };
    
        template <>
        struct printer<0>
        {
            template <typename TUPLE>
            void operator () (const TUPLE& t) const {}
        };
    
    }
    
    
    template <typename ... Ts>
    void print(const std::tuple<Ts...>& t)
    {
        detail::printer<sizeof...(Ts)>{}(t);
    }
    
  • 或使用index_sequence

    #if 1 // Not in C++11
    #include <cstdint>
    
    template <std::size_t...> struct index_sequence {};
    
    template <std::size_t N, std::size_t... Is>
    struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
    
    template <std::size_t... Is>
    struct make_index_sequence<0u, Is...> : index_sequence<Is...>{};
    
    #endif
    
    namespace detail
    {
    
        template <std::size_t... Is, typename TUPLE>
        void print(const TUPLE& t, index_sequence<Is...>)
        {
            int dummy[] = {0, ((std::cout << std::get<Is>(t) << std::endl), 0)...};
            (void) dummy; // To remove warning about unused variable.
        }
    
    }
    
    template <typename ... Ts>
    void print(const std::tuple<Ts...>& t)
    {
        detail::print(t, make_index_sequence<sizeof...(Ts)> {});
    }
    

【讨论】:

  • 我没有尝试第二个代码 sn-p 但第一个代码确实有效。谢谢。
【解决方案2】:

为了保留问题中给出的原始代码的结构,以下解决方法在 MSVC 2013 中适用于我:

定义以下助手:

// workaround for msvc `sizeof...(Tp)` not working
template<typename... Tp>
struct sizeof_pack___ { static const std::size_t value = sizeof...(Tp); };

然后将出现的两次sizeof...(Tp) 替换为sizeof_pack___&lt;Tp...&gt;::value

最终代码如下所示:

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I == sizeof_pack___<Tp...>::value, void>::type
    print(const std::tuple<Tp...>& t)
{ }

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I < sizeof_pack___<Tp...>::value, void>::type
    print(const std::tuple<Tp...>& t)
{
    std::cout << std::get<I>(t) << std::endl;
    print <i, Tp...> (t);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 2016-02-03
    相关资源
    最近更新 更多