【问题标题】:How to avoid decay with template parameter deduction如何通过模板参数推导避免衰减
【发布时间】:2016-12-22 20:10:24
【问题描述】:

简化:

// CHAR_TYPE == char, wchar_t, ...
template <typename CHAR_TYPE, unsigned CHAR_COUNT>
void Foo(CHAR_TYPE const (&value)[CHAR_COUNT]) noexcept
{
    TRACE("const ref array");
    // perform a bit of logic and forward...
}

template <typename CHAR_TYPE>
void Foo(CHAR_TYPE const* value) noexcept
{
    TRACE("const ptr");
    // perform a bit of logic and forward...
}

// [ several other overloads ]

调用点:

char const* ptr = ...
wchar_t const* wptr = ...

Foo(ptr);     // <-- good: "const ptr"
Foo(wptr);    // <-- good: "const ptr"

constexpr char const buffer[] { "blah blah blah" };
constexpr wchar_t const wbuffer[] { L"blah blah blah" };

Foo(buffer);  // <-- ambiguous
Foo(wbuffer); // <-- ambiguous

当然,我可以删除 const ref 数组重载。但是我想以不同的方式处理这些类型。我已经尝试有条件地启用正确的重载,但我无法确定必要的条件。

template <typename CHAR_TYPE, unsigned COUNT>
typename std::enable_if</* std::is_?? */, void>::type
    Foo(CHAR_TYPE const (&value)[COUNT]) noexcept
{
    TRACE("by ref array");
    // perform a bit of logic and forward...
}

template <typename CHAR_TYPE>
typename std::enable_if</* std::is_?? */, void>::type
    Foo(CHAR_TYPE const* value) noexcept
{
    TRACE("ptr");
    // perform a bit of logic and forward...
}

消除这些重载的最佳方法是什么?
(我宁愿不使用数组包装器)

【问题讨论】:

  • 这可能是一个愚蠢的问题,但是第一个模板应该如何隐式提取大小参数?
  • @MikelF 是通过模板类型推导完成的,数组的类型是char[N],而不是char*。数组并不总是衰减为指针。更好的说法是,通过引用传递的数组不会衰减。

标签: c++ c++11 templates sfinae


【解决方案1】:

一个可行的想法是删除指针并简单地使用T 代替std::enable_if_t&lt;std::is_pointer&lt;T&gt;::value&gt; 保护。下面的简化示例:

#include <iostream>
#include <type_traits>

template<class T, size_t N>
void f(T const (&) [N])
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

template<class T, std::enable_if_t<std::is_pointer<T>::value>* = nullptr >
void f(T)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    const char* str = "test";
    char str2[]{"test2"};

    f(str);
    f(str2);
}

Live on Coliru

【讨论】:

  • 完美。没有意识到这一点,我感到很尴尬。谢谢。
  • @Jeff 我不得不说,最初我会认为数组重载具有更高的排名。我仍然不知道为什么编译器认为这 2 个重载具有相似的等级。
  • 同意!我在逻辑中使用了 CHAR_TYPE(这可能是我想不出解决方案的原因),所以我还有更多需要解决的问题。再次感谢。
【解决方案2】:

在模板参数推导过程中,通过 (const) 引用阻止数组到指针的衰减。见[temp.deduct.call]/2。所以:

template <typename CHAR_TYPE>
void Foo(CHAR_TYPE const* const & value) noexcept
{
    TRACE("const ptr");
    // perform a bit of logic and forward...
}

【讨论】:

  • 这太棒了。事实证明,这非常有效,并且允许我继续使用 CHAR_TYPE。谢谢。
猜你喜欢
  • 2018-10-25
  • 2020-04-09
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多