【问题标题】:Template argument deduction with multiple transformations具有多个转换的模板参数推导
【发布时间】:2020-05-25 18:12:06
【问题描述】:

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

#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_extent 之后需要remove_cv

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

【问题讨论】:

  • _T_ 是在所有上下文中为 C++ 实现保留的标识符,因为它以一个下划线开头,后跟一个大写字母。使用这样的标识符会导致未定义的行为。我建议你不要使用它。 (只是T 是一个常用的模板参数名称,在这里就可以了。)
  • 我不确定你是如何设法得到你的替代方案来推断类型的。 _T_ 在这种情况下仍处于非推断上下文中,它应该给出相同的错误消息。
  • 无关:int main( void ) --> int main() - C++ 不是 C.
  • @walnut 没错,坏习惯很难改

标签: c++ templates type-inference typetraits template-argument-deduction


【解决方案1】:

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

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

您提供模板参数T。在

foo( "abc" );

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

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

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)};
    // ...
}

【讨论】:

  • 谢谢,std::forward 是最好的恕我直言
【解决方案2】:

也许你可以在模板参数列表中建立类型并在函数参数列表中以T作为参考

template<typename T, typename U = const std::basic_string<std::remove_cv_t<std::remove_extent_t<T>>>>
void foo
(
  T& t // deducible context
)
{
  U& u = t;
  std::cout << u << std::endl;
}

Godbolt demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 2022-12-22
    相关资源
    最近更新 更多