George T.
George T.

Reputation: 119

C++ templates: How to conditionally compile different code based on data type?

Here's a small example that illustrates the essence of my question:

#include <iostream>
using namespace std ;
typedef char achar_t ;

template < class T > class STRING
{
   public:
     T *    memory   ;
     int    size     ;
     int    capacity ;
   public:
     STRING() {
        size     =   0 ;
        capacity = 128 ;
        memory   = ( T *) malloc( capacity * sizeof(T) ) ;
     }
     const STRING& operator=( T * buf) {
         if ( typeid(T) == typeid(char) )
            strcpy( memory, buf ) ;
         else
            wcscpy( memory, buf ) ;
        return *this ;
     }
}  ;

void main()
{
  STRING<achar_t> a ;
  STRING<wchar_t> w ;
  a =  "a_test" ;
  w = L"w_test" ;
 cout << " a = " << a.memory << endl ;
 cout << " w = " << w.memory << endl ;
}

Can some one please help me compile the above? That is somehow compile either with strcpy() or wcscpy() based on the type of the object i am using.

thank you

Upvotes: 5

Views: 2419

Answers (3)

zett42
zett42

Reputation: 27806

Use std::char_traits<CharT>.

You can replace strcpy() and wcscpy() by combining the static methods std::char_traits::length() and std::char_traits::copy(). This will also make your code more generic because std::char_traits has specializations for char16_t and char32_t.

 STRING& operator=( T const * buf) {
    // TODO: Make sure that buffer size for 'memory' is large enough.
    //       You propably also want to assign the 'size' member.        

    auto len = std::char_traits< T >::length( buf );
    std::char_traits< T >::copy( memory, buf, len );

    return *this ;
 }

Side notes:

  • I changed the type of parameter buf to T const* because it is not legal to assign a string literal to a pointer that points to non-const data. We only need read access to the data pointed to by buf.
  • I changed the return type to STRING& because that's the way how the assignment operator usually is declared. The method must be non-const so there is no point in restricting the return type to a constant reference.

Upvotes: 7

Ajay
Ajay

Reputation: 18441

If you are using C++17, you can use if constexpr also:

if constexpr (std::is_same<char, T>::value)
   strcpy( memory, buf );
else
   wcscpy( memory, buf );

The branch that fails the condition will not be compiled for the given template instantiation.

Upvotes: 6

jbalestr42
jbalestr42

Reputation: 74

You can use template specialization.

template<typename T>
class STRING {
public:
 T *    memory   ;
 int    size     ;
 int    capacity ;
public:
 STRING() {
    size     =   0 ;
    capacity = 128 ;
    memory   = ( T *) malloc( capacity * sizeof(T) ) ;
 }
STRING const & operator=(T * buf);
};

And you define a specialization for the type you want

template<> STRING<achar_t> const & STRING<achar_t>::operator=(achar_t * buf)
{
    strcpy(memory, buf );
    return *this;
}

template<> STRING<wchar_t> const & STRING<wchar_t>::operator=(wchar_t * buf)
{
    wcscpy( memory, buf );
    return *this;
}

I didn't test this code but you can find more information here http://en.cppreference.com/w/cpp/language/template_specialization

Upvotes: 0

Related Questions