Congelli501
Congelli501

Reputation: 2603

How to instantiate only part of a function template if a condition is true

Is it possible to build only some part of the code given the type of the template in C++ ? It would be something lake that :

#include <iostream>

using namespace std;

template<typename T>
void printType(T param)
{
    #if T == char*
        cout << "char*" << endl;
    #elif T == int
        cout << "int" << endl;
    #else
        cout << "???" << endl;
    #endif
}

int main()
{
    printType("Hello world!");
    printType(1);
    return 0;
}

Upvotes: 56

Views: 42168

Answers (5)

Wormer
Wormer

Reputation: 735

Since C++17 there is a way to do exactly this with if-constexpr. The following compiles since clang-3.9.1, gcc-7.1.0, and recent MSVC compiler 19.11.25506 handles well too with an option /std:c++17.

#include <iostream>
#include <type_traits>

template<typename T>
void printType(T)
{
    if constexpr (std::is_same_v<T, const char*>)
        std::cout << "const char*" << std::endl;
    else if constexpr (std::is_same_v<T, int>)
        std::cout << "int" << std::endl;
    else
        std::cout << "???" << std::endl;
}

int main()
{
    printType("Hello world!");
    printType(1);
    printType(1.1);
    return 0;
}

Output:

const char*
int
???

Upvotes: 28

Xeo
Xeo

Reputation: 131897

Type traits:

#include <iostream>
#include <type_traits> // C++0x
//#include <tr1/type_traits> // C++03, use std::tr1

template<typename T>
void printType(T param)
{
  if(std::is_same<T,char*>::value)
        std::cout << "char*" << endl;
  else if(std::is_same<T,int>::value)
        std::cout << "int" << endl;
  else
        std::cout << "???" << endl;
}

Or even better yet, just overload the function:

template<class T>
void printType(T partam){
  std::cout << "???" << endl;
}

void printType(char* partam){
  std::cout << "char*" << endl;
}

void printType(int partam){
  std::cout << "int" << endl;
}

Partial ordering will take care that the correct function is called. Also, overloading is preferred to template specialization in the general case, see this and this artice for why. Might not apply for you if you totally have to print the type, as implicit conversions are considered for overloaded functions.

Upvotes: 60

Jesse Emond
Jesse Emond

Reputation: 7490

You use template specification to specify versions of your function to work differently based on its type. For example, you can make a generic version of a function that would work with most types, and make a specific version for e.g. int that will be faster. You'd do it this way:

template <class T>
void printType(T param)
{
    cout<<"Generic version"<<endl;
}
template <>
void printType<int>(int param)
{
    cout<<"Int version"<<endl;
}
template <>
void printType<char>(char param)
{
    cout<<"Char version"<<endl;
}
//Rince and repeat.

Upvotes: 4

Puppy
Puppy

Reputation: 147036

You can use a specialization. The preprocessor runs before all templates and cannot interact with them.

template<typename T> void printType(T t) {
    std::cout << typeid(T).name(); // fallback
}
template<> void printType<char*>(char* ptr) {
    std::cout << "char*";
}
template<> void printType<int>(int val) {
    std::cout << "int";
}

Upvotes: 6

Alexander Gessler
Alexander Gessler

Reputation: 46657

Use template specialization:

template<typename T>
void printType(T param)
{
   // code for the general case - or omit the definition to allow only the specialized types
}

template<>
void printType<char*>(char* param)
{
   // code for char*
}

template<>
void printType<int>(int param)
{
   // code for int    
}

// ...

Upvotes: 11

Related Questions