简体   繁体   中英

compile time check template type C++

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.

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

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.

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.

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?

There are two ways to solve this problem.

  1. Add addNumeric() to String . This is the easiest solution if you have permission to modify String .
  2. If you don't have permission to modify String , you can use a helper class to help with the process.

Here's the helper class.

template <typename T1> struct IsNumeric
{
   static bool get(T1 const& temp)
   {
      return false;
   }
};

template <> struct IsNumeric<Numeric>
{
   static bool get(Numeric const& temp)
   {
      return temp.isNumeric();
   }
};

Here's your main class:

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

    public:

    void checkNumeric()
    {
       std::cout << " is numeric = " << IsNumeric<T>::get(temp) << std::endl;
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM