首页 > 解决方案 > 具有多个转换的模板参数推导

问题描述

我正在尝试编写一个泛型函数,其参数包含模板类型的多个转换,例如:

#include <iostream>
#include <string>
#include <type_traits>

template< typename _T_ >
void foo
(
     const std::basic_string< typename std::remove_cv< typename std::remove_extent< _T_ >::type >::type > & str
)
{
    std::cout << str << std::endl;
}

int main( void )
{
    foo< char const [ 3 ] >( "abc" ); // OK
    foo( "abc" );                     // Cannot deduce template argument

    return 0;
}

不幸的是,编译器无法推断出正确的类型。
使用最新版本的 Clang、GCC 和 MSVC 进行测试。

有趣的是,编译器似乎能够通过一种转换进行推断:

 const std::basic_string< typename std::remove_extent< _T_ >::type > & str

显然,上面的例子失败了,因为const,因此需要remove_cvafter remove_extent

这是预期的吗,有什么方法可以实现吗?

标签: c++templatestype-inferencetypetraitstemplate-argument-deduction

解决方案


包含qualified-id的复杂名称是C++ 中的非推导上下文。在

foo< char const [ 3 ] >( "abc" );

您提供模板参数T。在

foo( "abc" );

T不能推导出模板参数(函数参数与模板参数是分开的,因此T不会从 推导出来"abc")。

一种解决方案是先推导出模板参数,然后basic_string在参数为 a 时构造const CharT*

template <class CharT>
void foo(const std::basic_string<CharT>& string)
{
    // ...
}

template <class CharT>
void foo(const CharT* p)
{
    std::basic_string<CharT> s{p};
    foo(s);
}

另一种解决方案是简单地依靠类模板参数推导来处理这两种情况:

template <class Arg>
void foo(Arg&& arg)
{
    std::basic_string s{std::forward<Arg>(arg)};
    // ...
}

推荐阅读