Clang候选模板被忽略:替换失败(也无法用gcc编译,VC工作正常)

时间:2016-07-16 00:44:50

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

我遇到了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&amp; storage),即使它很明显存在(并且VC可以找到它)我真的很感激。我对Clang和gcc很新。谢谢!

1 个答案:

答案 0 :(得分:3)

你有一个out_from_storage重载,可以调用而不显式提供模板参数,它依赖于:

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

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

由于没有可行的过载,呼叫失败。