std::enable_if 在模板 class 中用于同名函数时生成错误
std::enable_if is generating error when used on functions of same name inside a template class
问题描述
我正在尝试调用 returns 1
或 2
的函数,具体取决于类型是 signed char
还是 unsigned int
。
为此,我写了下面的代码。如果我编译代码没有main
里面的代码。我没有编译错误。
但是当我用对象的实例化编译代码时Coverage
,我得到以下编译错误:
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;
我知道当我们添加 typename std::enable_if
作为函数参数时,它没有被考虑在内。当我们有同名的成员函数时,它也是唯一的使用方法。
源代码
#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;
}
在这种情况下,最简单的解决方案是使用易于专门化的助手 class,并在助手 class 中实现方法,或者让助手 class 调用原始模板中的真实方法,通过传入的 this
指针。例如:
#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;
}
就像@Evg 提到的那样,您还需要对成员函数进行模板化。
此外,您需要为它们提供默认值,如通常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;
}
};
或者为每个函数提供一个trailing return SFINAE
#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;
};
未指定标准修订标签,所以让我添加一个 C++20 解决方案:
int getNb()
requires std::is_signed_v<T> {
return 1;
}
int getNb()
requires std::is_unsigned_v<T> {
return 2;
}
如果 C++17 是一个选项,您可以避免 std::enable_if
并改用 if constexpr
。
template<typename T>
class Coverage {
// ...
static constexpr int getNb() {
if constexpr ( std::is_unsigned_v<T> )
return 2;
else
return 1;
}
// ...
};
您甚至可以将其设为静态成员变量,而不是函数
template<typename T>
class Coverage {
// ...
static constexpr int Nb{ std::is_unsigned_v<T> ? 2 : 1 };
// ...
};
问题描述
我正在尝试调用 returns 1
或 2
的函数,具体取决于类型是 signed char
还是 unsigned int
。
为此,我写了下面的代码。如果我编译代码没有main
里面的代码。我没有编译错误。
但是当我用对象的实例化编译代码时Coverage
,我得到以下编译错误:
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;
我知道当我们添加 typename std::enable_if
作为函数参数时,它没有被考虑在内。当我们有同名的成员函数时,它也是唯一的使用方法。
源代码
#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;
}
在这种情况下,最简单的解决方案是使用易于专门化的助手 class,并在助手 class 中实现方法,或者让助手 class 调用原始模板中的真实方法,通过传入的 this
指针。例如:
#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;
}
就像@Evg 提到的那样,您还需要对成员函数进行模板化。
此外,您需要为它们提供默认值,如通常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;
}
};
或者为每个函数提供一个trailing return SFINAE
#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;
};
未指定标准修订标签,所以让我添加一个 C++20 解决方案:
int getNb()
requires std::is_signed_v<T> {
return 1;
}
int getNb()
requires std::is_unsigned_v<T> {
return 2;
}
如果 C++17 是一个选项,您可以避免 std::enable_if
并改用 if constexpr
。
template<typename T>
class Coverage {
// ...
static constexpr int getNb() {
if constexpr ( std::is_unsigned_v<T> )
return 2;
else
return 1;
}
// ...
};
您甚至可以将其设为静态成员变量,而不是函数
template<typename T>
class Coverage {
// ...
static constexpr int Nb{ std::is_unsigned_v<T> ? 2 : 1 };
// ...
};