Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

compile time check template type C++

Tags:

c++

std

templates

I am trying to check a template type and appropriate invoke a function. However, this doesn't seem to work. I tried with is_same, C++ compile-time type checking, compile-time function for checking type equality and the boost::is_same. Everything is giving me the same error. The following is a sample code.

#include <iostream>
#include <type_traits>
using namespace std;

class Numeric
{
public :
    bool isNumeric()
    {
    return true;
    }
};
class String
{

};

template <class T>
class Myclass
{
    private:
    T temp;
    public:
    void checkNumeric()
    {
        if(std::is_same<T,Numeric>::value)
        {
            cout << "is numeric = " << temp.isNumeric();
        }
        else
        {
            cout << "is numeric = false" << endl;
        }
    }

};

int main()
{
    Myclass<Numeric> a;
    a.checkNumeric();
    Myclass<String> b;
    b.checkNumeric();
}

While compiling the above code, I am getting the following error.

make all 
Building file: ../src/TestCPP.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/TestCPP.d" -MT"src/TestCPP.d" -o "src/TestCPP.o" "../src/TestCPP.cpp"
../src/TestCPP.cpp:36:36: error: no member named 'isNumeric' in 'String'
                    cout << "is numeric = " << temp.isNumeric();
                                               ~~~~ ^
../src/TestCPP.cpp:51:4: note: in instantiation of member function               'Myclass<String>::checkNumeric' requested here
    b.checkNumeric();
      ^
1 error generated.
make: *** [src/TestCPP.o] Error 1

In this case, I neither have String or Numeric class. It comes out of a third party library. I implement only MyClass which will be packaged as another library. I expect the application that uses MyClass will either pass me a String or Numeric which belongs to a third party class. MyClass is a specialized matrix operation and Dense/Sparse matrix are the Numeric and String like classes that comes from a third party library. I want to check if the application that uses my library and the third party library is invoking MyClass based on the class type that belongs to the third party library.

Kindly let me know how to fix this problem.

like image 990
Ramakrishnan Kannan Avatar asked Feb 27 '14 23:02

Ramakrishnan Kannan


4 Answers

No need to do anything fancy; this can be handled using ordinary template specialization.

template <class T>
class Myclass
{
    private:
    T temp;

    public:
    // called for general T
    void checkNumeric() {
        cout << "is numeric = false" << endl;
    }
};

// specialized version for T = Numeric
template<> void Myclass<Numeric>::checkNumeric() {
    cout << "is numeric = " << temp.isNumeric() << endl;
}
like image 124
Brian Bi Avatar answered Sep 20 '22 23:09

Brian Bi


You need to select enable/disable functions during compilation, not during run-time. I suggest doing something like that (code on ideone.com):

#include <iostream>
#include <type_traits>

class Numeric {
 public:
  bool isNumeric() {
   return true;
  }
};

class String {
};

template<class T>
class Myclass {
 private:
  T temp;
 public:
  template<typename U = T, typename std::enable_if<std::is_same<U, Numeric>::value, std::size_t>::type = 0>
  void checkNumeric() {
   std::cout << "is numeric = " << temp.isNumeric() << std::endl;
  }

  template<typename U = T, typename std::enable_if<!std::is_same<U, Numeric>::value, std::size_t>::type = 0>
  void checkNumeric() {
   std::cout << "is numeric = false" << std::endl;
  }
};

int main() {
 Myclass<Numeric> a;
 a.checkNumeric();
 Myclass<String> b;
 b.checkNumeric();
}

Program output:

is numeric = 1
is numeric = false

Hope this helps.

like image 23
lapk Avatar answered Sep 20 '22 23:09

lapk


The if else will force the compiler to instantiate both control flows. Since there are cases where T is not a Numeric type (even though code may not run through that path), this wll cause a compile error. What you need is a compile time control flow, something in the lines of if_then_else

template<int condition, int true_val, int false_val>
struct if_then_else {
    enum { val = true_val };
};

template<int true_val, int false_val>
struct if_then_else<false, true_val, false_val> {
    enum { val = false_val };
};

Then if_then_else< std::is_same<T, Numeric>::value, 1, 0>::value would give 1(true) for Numeric types and 0(false) with non numeric ones without the need to invalidly instantiate the non numeric.

like image 23
Nikos Athanasiou Avatar answered Sep 19 '22 23:09

Nikos Athanasiou


MyClass<T>::checkNumeric() calls T::isNumeric(). Your String class does not have such a function, so MyClass<String>::checkNumeric() does not compile.

options:

  • Add and implement String::isNumeric().
  • you're already getting your answer from std::is_same, so why call isNumeric() at all?
like image 23
Adam Avatar answered Sep 19 '22 23:09

Adam