Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid decay with template parameter deduction

Simplified:

// 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

Of course, I could remove the const ref array overload. However I would like to handle these types differently. I have tried to conditionally enable the correct overload, but I have not been able to determine the necessary condition.

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...
}

What is the best way to disambiguate these overloads?
(I would prefer not to use an array wrapper)

like image 863
Jeff Avatar asked Dec 22 '16 20:12

Jeff


People also ask

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

What is template argument deduction?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

What is STD decay?

std::decay Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T , removes cv-qualifiers, and defines the resulting type as the member typedef type . Formally: If T names the type "array of U " or "reference to array of U ", the member typedef type is U*.

Can a template be a template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)


1 Answers

One idea that works is to remove the pointer and simply have T instead, with a std::enable_if_t<std::is_pointer<T>::value> guard. Simplified example below:

#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

like image 98
vsoftco Avatar answered Oct 18 '22 10:10

vsoftco