Как избежать распада с вычитанием параметра шаблона
Упрощенная:
// 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 ]
Callsite:
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...
}
Каков наилучший способ устранить эти перегрузки?
(Я бы предпочел не использовать оболочку массива)
Ответы
Ответ 1
Взятие аргумента с помощью (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...
}
Ответ 2
Одна из идей, которая работает, заключается в удалении указателя и просто T
, а с защитой std::enable_if_t<std::is_pointer<T>::value>
. Упрощенный пример ниже:
#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