Reputation: 185
I have the following code which works, when I compile the code with C++11 enabled. Is it also possible to write the specializations such that it will work with a C++98 compiler?
#include <iostream>
#include <type_traits>
#include <cstdint>
template<typename T, typename std::enable_if_t<!std::is_pointer<T>::value, int> = 0>
void CheckSize(T const)
{
cout << "sizeof(data): " << sizeof(T) << endl;
}
template<typename T, typename std::enable_if_t<std::is_pointer<T>::value, int> = 0>
void CheckSize(T const)
{
cout << "sizeof(data) (pointer): " << sizeof(std::remove_pointer<T>) << endl;
}
template<typename T, size_t N>
void CheckSize(T const (&)[N])
{
cout << "sizeof(data) (array): " << sizeof(T) * N << endl;
}
int main()
{
uint8_t bufferNumber{0};
CheckSize(bufferNumber);
uint8_t bufferArray[] = {1,2,3,4,5,6};
CheckSize(bufferArray);
uint8_t *bufferPointer{nullptr};
CheckSize(bufferPointer);
return 0;
}
I also don't understand why the compiler can't apply the specialization when writing:
template<typename T>
void CheckSize(T const)
{
cout << "sizeof(data): " << sizeof(T) << endl;
}
template<typename T>
void CheckSize(T const*)
{
cout << "sizeof(data) (pointer): " << sizeof(T) << endl;
}
MSVC2015 will print an error message that the function call is ambigious for the overloaded function for the bufferArray
variable and MinGW will use the CheckSize(T const)
function for the bufferPointer
variable.
Upvotes: 2
Views: 390
Reputation: 30569
As mentioned in the comments, enable_if
and the type traits you're using are implementable using C++98. Boost provides implementations, and I would recommend using them if you're already using boost, but they're fairly simple to implement if you're not using boost:
template <bool b, typename T>
struct enable_if;
template <typename T>
struct enable_if<true, T>
{
typedef T type;
};
template <typename T>
struct is_pointer
{
const static bool value = false;
};
template <typename T>
struct is_pointer<T*>
{
const static bool value = true;
};
template <typename T>
struct remove_pointer
{
typedef T type;
};
template <typename T>
struct remove_pointer<T*>
{
typedef T type;
};
template<typename T>
typename enable_if<!is_pointer<T>::value, void>::type
CheckSize(T const)
{
std::cout << "sizeof(data): " << sizeof(T) << std::endl;
}
template<typename T>
typename enable_if<is_pointer<T>::value, void>::type
CheckSize(T const)
{
std::cout << "sizeof(data) (pointer): " << sizeof(typename remove_pointer<T>::type) << std::endl;
}
template<typename T, size_t N>
void CheckSize(T const (&)[N])
{
std::cout << "sizeof(data) (array): " << sizeof(T) * N << std::endl;
}
Alternatively, you could use partial specialization rather than SFINAE to select your overload. Since functions can't be partially specialized, you can partially specialize a helper class:
template<typename T>
struct CheckSizeHelper
{
static void size() {
std::cout << "sizeof(data): " << sizeof(T) << std::endl;
}
};
template<typename T>
struct CheckSizeHelper<T*>
{
static void size() {
std::cout << "sizeof(data) (pointer): " << sizeof(T) << std::endl;
}
};
template<typename T, size_t N>
struct CheckSizeHelper<T[N]>
{
static void size() {
std::cout << "sizeof(data) (array): " << sizeof(T) * N << std::endl;
}
};
template<typename T>
void CheckSize(T const&) {
CheckSizeHelper<T>::size();
}
Upvotes: 2
Reputation: 2324
As it was mentioned in the comments, one option is to use the boost::enable_if
Another option is to use partial template specialization for classes instead of function overloading:
#include <iostream>
#include <type_traits>
#include <cstdint>
using namespace std;
template<typename T>
struct SizeChecker
{
static void CheckSize(T const)
{
cout << "sizeof(data): " << sizeof(T) << endl;
}
};
template<typename T>
struct SizeChecker<T*>
{
static void CheckSize(T* const)
{
cout << "sizeof(data) (pointer): " << sizeof(T*) << endl;
}
};
template<typename T, size_t N>
struct SizeChecker<T[N]>
{
static void CheckSize(const T(&)[N])
{
cout << "sizeof(data) (array): " << sizeof(T) * N << endl;
}
};
template <typename T>
void CheckSize(const T& val)
{
SizeChecker<T>::CheckSize(val);
}
int main()
{
char bufferNumber{0};
CheckSize(bufferNumber);
char bufferArray[] = {1,2,3,4,5,6};
CheckSize(bufferArray);
char *bufferPointer{NULL};
CheckSize(bufferPointer);
return 0;
}
Upvotes: 1