4

I would like to provide different implementations of a function dependant on if it is a pointer, a reference or a regular type. This is my code so far:

template<class T,
         class = typename std::enable_if_t<std::is_reference<T>::value>>
void f(T && in)
{}

// This causes redefinition error 
template<class T,
    class = typename std::enable_if_t<std::is_pointer<T>::value>>
void f(T && in)
{}

template<class T,
    class = typename std::enable_if_t<!std::is_reference<T>::value>,
    class = typename std::enable_if_t<!std::is_pointer<T>::value>>
void f(T && in)
{}

The middle function causes:

12:13: error: redefinition of 'template void f(T&&)'

7:13: note: 'template void f(T&&)' previously declared here

Funnily only the first and last function together compile.

Any ideas how to fix it or simplify this code.

5
  • Default template parameters are not part of template signature. So of these 3 templates first two have the same signature, while third one takes 3 template parameters. Commented Nov 28, 2018 at 16:18
  • 2
    Why not just have the overloads void f(T*), void f(T&), and void f(T)? Commented Nov 28, 2018 at 16:19
  • @NathanOliver: How do I do void f(T&&) as not forwarding reference? I mean I could do the whole process reverse but not sure if it makes things easier. Commented Nov 28, 2018 at 16:23
  • @AndreasPasternak See Pete Becker's answer Commented Nov 28, 2018 at 16:27
  • @NathanOliver: You are right! Commented Nov 28, 2018 at 16:33

2 Answers 2

10

The usual way is to provide appropriate overloads:

#include <iostream>

template <class T> void f(T&&) {
    std::cout << "T&&\n";
}

template <class T> void f(T*) {
    std::cout << "T*\n";
}

template <class T> void f(T&) {
    std::cout << "T&\n";
}

int main() {
    int i;
    f(std::move(i));
    f(&i);
    f(i);
}

This produces the following output:

[temp]$ clang++ -std=c++11 test.cpp
[temp]$ ./a.out
T&&
T*
T&
[temp]$ 
Sign up to request clarification or add additional context in comments.

2 Comments

How do I deal with const references and pointers? Do I not need an additional overload for those then aswell?
@AndreasPasternak -- you need overloads for whichever types you want to distinguish. This answer addresses the types you mentioned in your question and in your code.
5

Template default argument values are not part of the signature, so you need to further disambiguate the overloads by - as an example - adding an extra dummy template parameter:

template<class T,
         class = typename std::enable_if_t<std::is_reference<T>::value>>
void f(T && in)
{}

// This causes redefinition error 
template<class T,
    class = typename std::enable_if_t<std::is_pointer<T>::value>, class = void>
void f(T && in)
{}

1 Comment

Great, this compiles. I'll accept if it also works as intended. Thank you so far!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.