Stack Overflow Asked by gringo on November 7, 2021
Problem description
I am trying to call a function that returns 1
or 2
depending on whether the type is signed char
or unsigned int
.
For this purpose, I wrote the following code. If I compile the code without the code inside the main
. I get no compilation error.
But when I compile the code with the instantiation of an object Coverage
, I get the following compilation errors:
main.cpp: In instantiation of ‘class Coverage<unsigned char>’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',27)">main.cpp:27:28</span>: required from here
main.cpp:12:9: error: no type named ‘type’ in ‘struct std::enable_if’
int getNb(typename std::enable_if<std::is_signed<T>::value, void>::type) {
^~~~~
main.cpp:17:9: error: invalid parameter type ‘std::enable_if::type {aka void}’
int getNb(typename std::enable_if<std::is_unsigned<T>::value, void>::type) {
^~~~~
main.cpp:17:9: error: in declaration ‘int Coverage::getNb(typename std::enable_if::value, void>::type)’
main.cpp: In function ‘int main()’:
main.cpp:28:18: error: ‘class Coverage’ has no member named ‘getNb’
std::cout << c.getNb() << std::endl;
I understood that when we add typename std::enable_if
as function argument it’s not taken into consideration. It is also the only way to use when we have member functions with the same name.
Source Code
#include <iostream>
#include <type_traits>
template<typename T>
class Coverage
{
public:
Coverage(T type) :_type(type) {}
// signed char
int getNb(typename std::enable_if<std::is_signed<T>::value, void>::type) {
return 1;
}
// unsigned int
int getNb(typename std::enable_if<std::is_unsigned<T>::value, void>::type) {
return 2;
}
private:
T _type;
};
int main()
{
Coverage<unsigned char> c('c');
std::cout << c.getNb() << std::endl;
return 0;
}
If C++17 is an option, you could avoid std::enable_if
and make use of if constexpr
instead.
template<typename T>
class Coverage {
// ...
static constexpr int getNb() {
if constexpr ( std::is_unsigned_v<T> )
return 2;
else
return 1;
}
// ...
};
You could even make it a static member variable, instead of a function
template<typename T>
class Coverage {
// ...
static constexpr int Nb{ std::is_unsigned_v<T> ? 2 : 1 };
// ...
};
Answered by Bob__ on November 7, 2021
The standard revision tag was not specified, so let me add a C++20 solution:
int getNb()
requires std::is_signed_v<T> {
return 1;
}
int getNb()
requires std::is_unsigned_v<T> {
return 2;
}
Answered by Evg on November 7, 2021
Like @Evg mentioned you have to need the member function to be templated as well.
In addition, you need to provide default values for them, like usual nullptr
defaulting.
#include <iostream>
#include <type_traits>
template<typename T>
class Coverage {
public:
Coverage(T type) :_type(type) {}
//signed char
template<typename Type = T> // templated the member!
int getNb(typename std::enable_if<std::is_signed<Type>::value, void>::type* = nullptr)
{
return 1;
}
//unsigned int
template<typename Type = T> // templated the member!
int getNb(typename std::enable_if<std::is_unsigned<Type>::value, void>::type* = nullptr)
{
return 2;
}
};
Or provide a trailing return SFINAE for each functions
#include <iostream>
#include <type_traits>
template<typename T>
class Coverage {
public:
Coverage(T type) :_type(type) {}
template<typename Type = T>
auto getNb() -> typename std::enable_if<std::is_signed<Type>::value, int>::type
{
return 1;
}
template<typename Type = T>
auto getNb() -> typename std::enable_if<std::is_unsigned<Type>::value, int>::type
{
return 2;
}
private:
T _type;
};
Answered by JeJo on November 7, 2021
The simplest solution in these kinds of cases is to use a helper class that's easily specialized, and implement the method in the helper class, or have the helper class invoke the real method in the original template, via a passed-in this
pointer. For example:
#include <iostream>
#include <type_traits>
template<bool> class coverage_helper;
template<>
class coverage_helper<true> {
public:
template<typename T>
static auto invoke_nb(T *this_p)
{
return this_p->get_nb_signed();
}
};
template<>
class coverage_helper<false> {
public:
template<typename T>
static auto invoke_nb(T *this_p)
{
return this_p->get_nb_unsigned();
}
};
template<typename T>
class Coverage{
public:
Coverage(T type):_type(type) {}
int getNb()
{
return coverage_helper<std::is_signed<T>::value>::invoke_nb(this);
}
int get_nb_signed()
{
return 1;
}
int get_nb_unsigned()
{
return 2;
}
private:
T _type;
};
int main()
{
Coverage<unsigned char> c('c');
std::cout << c.getNb() << std::endl;
return 0;
}
Answered by Sam Varshavchik on November 7, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP