在基于decltype的SFINAE表达式中使用MSVC++ 17.34(VS 22)的“未声明标识符”

ctzwtxfj  于 2022-11-27  发布在  其他
关注(0)|答案(1)|浏览(65)

我们正在尝试将一个C17项目从VS 19更新到VS 22,突然之间,我们的代码无法编译了。问题出现在foonathan/memory库的两个头文件中,与我们的代码相距甚远。该库自身的测试在VS 22下编译良好。以我有限的MSVC技能,我无法从错误消息中获得有关实际模板示例化的任何信息,这可能会有所帮助。
这些错误都是error C2065: '<some-identifier>': undeclared identifier,其中<some-identifier>是出现在旨在使用SFINAE的decltype表达式中的函数参数的名称。
4个位置之一是allocator_storage.hpp:140,摘录如下:

namespace foonathan::memory {
...
  template <class StoragePolicy, class Mutex>
  class allocator_storage
   : FOONATHAN_EBO(StoragePolicy, ...)
  {
    ...
    template <class OtherPolicy>
    allocator_storage(const allocator_storage<OtherPolicy, Mutex>& other,
      FOONATHAN_SFINAE(new storage_policy(other.get_allocator())))   // <--- HERE, this is line 140
      : storage_policy(other.get_allocator())
    {}
    ...
  };
...
}

我从MSVC得到的完整错误消息没有什么帮助,唯一的额外信息是示例化的模板的名称,没有实际的类型替换:

C:\...\foonathan\memory\allocator_storage.hpp(315): note: see reference to class template instantiation 'foonathan::memory::allocator_storage<StoragePolicy,Mutex>' being compiled
C:\...\foonathan\memory\allocator_storage.hpp(140): error C2065: 'other': undeclared identifier

由于FOONATHAN_SFINAE(Expr)被定义为decltype((Expr), int()) = 0(任何地方都看不到任何平台配置),在我看来,这个错误消息显然是错误的--这里有一个明显的other定义。
我在寻找关于这里发生了什么的任何提示,或者我可以做些什么来帮助理解这个问题。有没有一种方法可以让MSVC打印它正在替换到模板参数中的类型,就像现在的clang和gcc所做的那样?MSVC和基于decltype的SFINAE在方法参数中是否存在已知的问题?

r1zk6ea1

r1zk6ea11#

该问题的最小示例是(live on godbolt;感谢Maciej Polański,此代码基于original reproduction attempt

template <class StoragePolicy>
struct allocator_storage
{
  template <class OtherPolicy>
  allocator_storage(
        allocator_storage<OtherPolicy> const & other,
        decltype(new StoragePolicy(other.storage_policy), int()) = 0)
    : storage_policy(other.storage_policy)
  {
  }

  allocator_storage() = default;

  StoragePolicy storage_policy;
};

int main()
{
  allocator_storage<int> A{};    
  allocator_storage<long> B(A);    
}

clang和gcc都会编译它,但是MSVC在使用C++17 with /permissive-(但不在C++17 with /permissive中,在C++17中等于不指定任何内容)和C++20 (regardless of the permissive flag)时会导致错误。
最新的MSVC版本(19.33之后)提供了更多的信息,即

<source>(22): note: Failed to specialize function template 'allocator_storage<long>::allocator_storage(const allocator_storage<OtherPolicy> &,unknown-type)'
<source>(22): note: With the following template arguments:
<source>(22): note: 'OtherPolicy=int'
<source>(22): note: while trying to match the argument list '(allocator_storage<int>)'

而版本〈=19.33则不会显示此错误消息。不幸的是,它并没有提供更多的信息。
有一些bug reports on developer-community(例如thisthis)看起来相关,即使用SFINAE和decltype
考虑到所有这些(clang和gcc编译代码;现有的错误报告),我认为这肯定是MSVC中的一个错误。
前面已经提到了一种可能的解决方法,将decltype中对参数other的引用替换为std::declvalgodbolt):

decltype(
  new StoragePolicy(std::declval<allocator_storage<OtherPolicy>>().storage_policy), 
  int()) = 0

我注意到你已经在github上报告了这件事。

相关问题