2016-12-22 36 views
11

uproszczonej:Jak uniknąć próchnicy z parametrem szablonu odliczenia

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

Oczywiście, mogę usunąć const przeciążenie tablicy ref. Jednak chciałbym obsługiwać te typy w różny sposób. Próbowałem warunkowo włączyć poprawne przeciążenie, ale nie byłem w stanie określić koniecznego stanu.

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

Jaki jest najlepszy sposób na rozróżnienie tych przeciążeń?
(wolałbym nie używać opakowania array)

+0

To może być głupie pytanie, ale w jaki sposób pierwszy szablon ma domyślnie wyodrębnić parametr wielkości? –

+4

@MikelF Odbywa się to poprzez dedukcję typu szablonu, typem tablicy jest 'char [N]', a nie 'char *'. Tablice ** nie zawsze ** rozpadają się na wskaźniki. Lepiej powiedzieć, że tablice przekazywane przez referencje nie ulegają rozkładowi. – vsoftco

Odpowiedz

5

Biorąc argument rozpadu (const) blokuje odniesienia tablica-to-wskaźnik w odjęciu szablon argumentów. Zobacz [temp.deduct.call]/2. A więc:

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

To jest wyjątkowe. Jak się okazuje, działa to doskonale i pozwala mi nadal używać CHAR_TYPE. Dziękuję Ci. – Jeff

8

jeden pomysł, który działa jest usunięcie wskaźnika, a po prostu mieć T zamiast z std::enable_if_t<std::is_pointer<T>::value> straży. Przykład uproszczone następująco:

#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

+0

Idealny. Czuję się zawstydzony, nie zdając sobie z tego sprawy. Dziękuję Ci. – Jeff

+0

@Jeff Muszę powiedzieć, że początkowo pomyślałem, że przeciążenie tablicy ma wyższą rangę. Nadal nie wiem, dlaczego kompilator uważa, że ​​2 przeciążenia mają podobną rangę. – vsoftco

+0

Zgoda! Użyłem CHAR_TYPE w logice (być może dlatego nie mogłem wymyślić rozwiązania), więc będę miał nieco więcej do rozwiązania. Dzięki jeszcze raz. – Jeff