【问题标题】:Clang candidate template ignored: substitution failure (also fails to compile with gcc, VC works fine)Clang 候选模板被忽略:替换失败(也无法用 gcc 编译,VC 工作正常)
【发布时间】:2016-11-19 06:54:15
【问题描述】:

我遇到了 Clang 3.5 的问题。以下是一个独立的repro。此代码使用 VC12 编译。使用 Clang 我收到以下错误:

1>C:\Users\jcuyle\code\branches\dev\ClientSDK\test\CompilerTestbed\CompilerTestbed.cpp(111,5): error : no matching function for call to 'out_from_storage'
1>          }( util::out_from_storage( rv ) );
1>             ^~~~~~~~~~~~~~~~~~~~~~
1>  C:\Users\jcuyle\code\branches\dev\ClientSDK\test\CompilerTestbed\CompilerTestbed.cpp(37,13):  note: candidate template ignored: substitution failure [with storage_t = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > > &]: no matching function for call to 'out_from_storage'
1>  inline auto out_from_storage( storage_t && storage ) -> decltype( util::details::template out_from_storage( std::forward< storage_t >( storage ) ) )
1>              ^                                                     ~~~~
1>  1 error generated.

代码如下:

#include <stdint.h>

#include <type_traits>
#include <chrono>
#include <utility>

namespace util
{
namespace details
{

template< typename RTy, typename Ty, typename enable = void >
inline RTy out_from_storage( Ty );

template< typename Ty, typename = typename std::enable_if< std::is_trivial< typename std::decay< Ty >::type >::value, Ty >::type >
inline typename std::add_pointer< typename std::decay< Ty >::type >::type out_from_storage( Ty&& t )
{
    return &t;
}

} // namespace details

template< typename storage_t >
inline auto out_from_storage( storage_t && storage ) -> decltype( util::details::out_from_storage( std::forward< storage_t >( storage ) ) )
{
    return util::details::out_from_storage( std::forward< storage_t >( storage ) );
}

} // namespace util

namespace util
{
namespace details
{

template< typename enable = void >
inline int64_t out_from_storage( std::chrono::system_clock::time_point & storage )
{
    return std::chrono::system_clock::to_time_t( storage );
}

} // namespace details
} // namespace util

int main(int argc, char * argv[])
{
    std::chrono::system_clock::time_point out = std::chrono::system_clock::now( );
    util::out_from_storage( out ); // error
    util::details::out_from_storage( out ); // no error

    return 0;
}

虽然此示例相当简单,但代码是实用程序库的一部分,用于跨 DLL 边界封送类型。有许多类似的实用函数和大量针对不同类型的特化。在 VC 下一切正常,我怀疑 VC 接受的只是一些虚假的语法,但 Clang 和 gcc 需要稍微更正确才能接受。对代码进行重大的重新排序是困难的,并且对系统进行重大重写以使用完全不同的方法来专门化转换功能(例如,抽出 type_traits/enable_if 并使用标签调度或类似的方法)是不切实际的。如果有人可以解释为什么 Clang 找不到匹配的函数调用 util::details::out_from_storage( std::chrono::system_clock::time_point & storage ) 即使它很明显存在(并且 VC 可以找到它)我真的很感激。我对 Clang 和 gcc 很陌生。谢谢!

【问题讨论】:

  • 请提供minimal reproducible example,这里有很多代码与您遇到的问题完全无关。
  • 注: util::details::template out_from_storage( 在这两个地方都可以而且应该是 util::details::out_from_storage(
  • 作为一般规则,如果 MSVC 不同意 GCC 和/或 clang,则 MSVC 是错误的。
  • 实际上,您可能想要std::is_trivially_copyable而不是std::is_trivial

标签: c++ c++11 gcc clang clang++


【解决方案1】:

您有一个 out_from_storage 重载,无需显式提供模板参数即可调用,它依赖于:

std::is_trivial< typename std::decay< Ty >::type >::value

您使用time_point 的实例调用它,但这不是一个平凡的类型,因为它没有平凡的default constructor。因此,这个重载被从集合中移除。

由于没有可行的过载,调用失败。

【讨论】:

  • util::details::out_from_storage 有两个重载,都不需要模板参数。您是正确的,依赖于 std::is_trivial&lt; typename std::decay&lt; Ty &gt;::type &gt;::value 的重载不匹配,因为 time_point 不是微不足道的(这是故意的),但 template&lt; typename enable = void &gt; inline auto out_from_storage( std::chrono::system_clock::time_point &amp; storage ) -&gt; decltype( util::details::make_out_helper( storage ) ) 匹配,而且它也不需要模板参数。
  • 如果我将 main 更改为:int main(int argc, char * argv[]) { // auto tp = sample::time::CurrentTime( ); std::chrono::system_clock::time_point out; util::details::out_from_storage( out ); return 0; } 它编译得很好。这个问题与 util::out_from_storage 有关。
  • @JohnCuyle util::details::out_from_storage三个 重载。也许这就是你困惑的根源。
  • 在精简的复制中,我只看到两个,除非您计算没有实现的前向声明。一种采用任何类型,只要它满足enable_if 的要求,另一种采用time_point。由于后者是完全匹配的,而前者不会专门化,所以它应该是唯一的选择。如果我调用util::details::out_from_storage,编译器会选择正确的重载,但如果我调用util::out_from_storage,然后调用util::details::out_from_storage,它不会选择正确的重载,它会通知我不正确的重载将不起作用。
猜你喜欢
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多