【问题标题】:Why does "using namespace" try to instantiate templates in that namespace for MSVC为什么“使用命名空间”会尝试在该命名空间中为 MSVC 实例化模板
【发布时间】:2019-01-15 14:05:59
【问题描述】:

我有以下代码示例(MSVC 2015 编译)

https://godbolt.org/g/kccgtb(用于可执行演示)

#include "boost/range/value_type.hpp"

namespace foo { 

    template <typename Range>
    typename boost::range_value<Range>::type
    operator|(Range const& r, int holder)
    {       
    }

}

using namespace foo;


int main(){

}

在msvc下产生如下错误

example.cpp

/opt/compiler-explorer/windows/19.00.24210/include/xlocale(341): 警告 C4530:使用了 C++ 异常处理程序,但展开语义是 未启用。指定 /EHsc

/opt/compiler-explorer/libs/boost_1_67_0\boost/range/value_type.hpp(26): 错误 C2039:“类型”:不是 'boost::range_iterator'

    with

    [

        T=unsigned __int64

    ]

/opt/compiler-explorer/libs/boost_1_67_0\boost/range/value_type.hpp(26): 注意:参见'boost::range_iterator'的声明

    with

    [

        T=unsigned __int64

    ]

/opt/compiler-explorer/windows/19.00.24210/include/xstring(1659): 注意:参见类模板实例化的参考 'boost::range_value' 正在编译

/opt/compiler-explorer/windows/19.00.24210/include/xstring(1658): 注意:在编译类模板成员函数'void std::basic_string,std::allocator>::shrink_to_fit(void)'

/opt/compiler-explorer/windows/19.00.24210/include/system_error(661): 注意:参见对函数模板实例化的参考 'void std::basic_string,std::allocator>::shrink_to_fit(void)' 正在编译

/opt/compiler-explorer/windows/19.00.24210/include/stdexcept(21): 注意:参见类模板实例化的参考 'std::basic_string,std::allocator>' 正在编译

/opt/compiler-explorer/libs/boost_1_67_0\boost/range/value_type.hpp(26): 错误 C2146:语法错误:在标识符“类型”之前缺少“>”

/opt/compiler-explorer/libs/boost_1_67_0\boost/iterator/iterator_traits.hpp(23): 错误 C2039:“value_type”:不是 'std::iterator_traits'

    with

    [

        Iterator=int

    ]

/opt/compiler-explorer/libs/boost_1_67_0\boost/iterator/iterator_traits.hpp(23): 注意:参见 'std::iterator_traits' 的声明

    with

    [

        Iterator=int

    ]

/opt/compiler-explorer/libs/boost_1_67_0\boost/range/value_type.hpp(27): 注意:参见类模板实例化的参考 'boost::iterators::iterator_value' 正在编译

/opt/compiler-explorer/libs/boost_1_67_0\boost/iterator/iterator_traits.hpp(23): 错误 C3646:“类型”:未知的覆盖说明符

/opt/compiler-explorer/libs/boost_1_67_0\boost/iterator/iterator_traits.hpp(23): 错误 C4430:缺少类型说明符 - 假定为 int。注意:C++ 没有 支持默认整数

编译器返回:2

在 gcc 和 clang 下编译。

https://godbolt.org/g/kccgtb

【问题讨论】:

  • AFAIK 这是一个 msvc 错误。它通常与通用operator| 存在问题 - 例如,它尝试将其与 stl 标头内的内部标志匹配(偶然发现它并放弃尝试)。这是一个需要解决的烂摊子
  • @bartop msvc 在启用标准一致性模式时编译给定的代码 sn-p 很好。
  • @VTT 这很奇怪,但对我来说并不奇怪,特别是考虑到 msvc 2015 不支持 C++17。编辑:godbolt 上的最新 msvc 似乎没有给出编译错误。这显然是编译器错误

标签: c++ templates boost


【解决方案1】:

其中一种方法是在模板参数中使用 SFINAE:

template <class Range, class = std::enable_if_t<!std::is_fundamental_v<Range>>>
typename boost::range_value<Range>::type
operator|(
   const Range &r
  , int holder)
{ 
}

它比带有sfinae参数的更简洁,更少模糊

【讨论】:

    【解决方案2】:

    我有一个工作同事的工作。这很丑,但似乎有效

    #include "boost/range/value_type.hpp"
    
    namespace foo { 
    
        template <typename Range>
        typename boost::range_value<Range>::type
        operator|(
           typename std::enable_if<!std::is_fundamental<Range>::value, Range>::type 
              const& r
          , int holder)
        { 
        }
    }
    
    using namespace foo;
    
    int main(){}
    

    【讨论】:

    • 在模板参数或返回类型中做 sfinae 可能不那么难看
    • 这不仅丑,而且破。 operator| 函数的行为发生了变化,因为模板参数不能再被推导,这意味着它不能再用作普通运算符,只能使用类似operator|&lt;R&gt;(a,b) 的语法。所以@bartop 是正确的:SFINAE 逻辑真的不应该在参数类型中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 2020-11-24
    • 2021-11-10
    • 2014-11-14
    • 1970-01-01
    相关资源
    最近更新 更多