检查 class 是否有带有特定模板的 operator() 的方法
The way to check that class has operator() with specific template
我正在尝试使用 SFINAE 技术来检查 - class/struct 是否具有 operator()
以及特定的模板声明,例如(略微简化):
struct Simplified
{
// 1st operator - I need to detect its presence
template<typename T, int I>
void operator()(T& val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::to_string(I) << std::endl;
}
// 2nd operator
void operator()(double& val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::endl;
}
};
而且我无法检查 operator()
模板化签名。这是我的帮手 class:
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
struct Exists { };
struct NotExists { };
template<typename U, void(U::*)(T&, double)> struct SFINAESimple {};
template<typename U> static Exists Test(SFINAESimple<U, &(U::operator())>*);
// The problem is probably there ^^^^^^^^^^^^^^^
template<typename U> static NotExists Test(...);
public:
static constexpr bool kExists = std::is_same<decltype(Test<Fn>(nullptr)), Exists>::value;
};
但是这个class只能检测到非模板operator()
的存在。
// true if 2nd operator declared in Simplified class, false otherwise.
auto DoubleOpValid = TemplatedOperatorCheck<Simplified, 0, double>::kExists;
// always false
auto IntOpValid = TemplatedOperatorCheck<Simplified, 0, int>::kExists;
我做错了什么?在 Google 或 Whosebug 找不到任何相关内容...
提前致谢!任何帮助将不胜感激。
嗯...不确定您到底想要什么但是...我提出以下建议 class
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
template<typename U, void(U::*)(T&, double)>
struct SFINAESimple
{ };
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::operator()>*, int);
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::template operator()<T, I>>*, long);
template<typename U>
static std::false_type Test(...);
public:
static constexpr bool kExists = decltype(Test<Fn>(nullptr, 0))::value;
};
一些观察,没有特别的顺序...
您可以使用std::true_type
和std::false_type
,而不是Exist
和NotExist
;因此 kExists
初始化得到简化,不再需要 std::is_same
。
第二个模板参数调用 SFINAESimple
的正确语法是没有括号。我的意思是:&U::operator()
,不是&(U::operator())
您的 Test()
函数,将模板参数 &U::operator()
传递给 SFINAESimple
,适用于 non-template 函数;如果你希望它也适用于模板函数,你必须从可能的函数集中生成所需的函数,所以我添加了另一个传递 &U::template operator()<T, I>
参数的 Test()
函数
鉴于 class 可以同时具有模板和 non-template 函数,编译器 select 两个 Test()
函数返回 std::true
并给出一个错误,因为它不知道哪个更喜欢;为了允许编译器更喜欢一个版本或另一个版本,我添加了另一个参数(一个是 int
,另一个是 long
),因此调用 Test<Fn>(nullptr, 0)
,编译器更喜欢 int
版本(因为0
,第二个参数,是一个int
),避免歧义,避免错误。
下面是一个完整的编译示例
#include <iostream>
struct Simplified
{
// 1st operator - I need to detect its presence
template<typename T, int I>
void operator()(T & val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::to_string(I) << std::endl;
}
// 2nd operator
void operator()(double & val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::endl;
}
};
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
template<typename U, void(U::*)(T&, double)>
struct SFINAESimple
{ };
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::operator()>*, int);
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::template operator()<T, I>>*, long);
template<typename U>
static std::false_type Test(...);
public:
static constexpr bool kExists = decltype(Test<Fn>(nullptr, 0))::value;
};
int main()
{
auto DoubleOpValid = TemplatedOperatorCheck<Simplified, 0, double>::kExists;
auto IntOpValid = TemplatedOperatorCheck<Simplified, 0, int>::kExists;
std::cout << DoubleOpValid << ' ' << IntOpValid << '\n';
}
我正在尝试使用 SFINAE 技术来检查 - class/struct 是否具有 operator()
以及特定的模板声明,例如(略微简化):
struct Simplified
{
// 1st operator - I need to detect its presence
template<typename T, int I>
void operator()(T& val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::to_string(I) << std::endl;
}
// 2nd operator
void operator()(double& val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::endl;
}
};
而且我无法检查 operator()
模板化签名。这是我的帮手 class:
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
struct Exists { };
struct NotExists { };
template<typename U, void(U::*)(T&, double)> struct SFINAESimple {};
template<typename U> static Exists Test(SFINAESimple<U, &(U::operator())>*);
// The problem is probably there ^^^^^^^^^^^^^^^
template<typename U> static NotExists Test(...);
public:
static constexpr bool kExists = std::is_same<decltype(Test<Fn>(nullptr)), Exists>::value;
};
但是这个class只能检测到非模板operator()
的存在。
// true if 2nd operator declared in Simplified class, false otherwise.
auto DoubleOpValid = TemplatedOperatorCheck<Simplified, 0, double>::kExists;
// always false
auto IntOpValid = TemplatedOperatorCheck<Simplified, 0, int>::kExists;
我做错了什么?在 Google 或 Whosebug 找不到任何相关内容...
提前致谢!任何帮助将不胜感激。
嗯...不确定您到底想要什么但是...我提出以下建议 class
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
template<typename U, void(U::*)(T&, double)>
struct SFINAESimple
{ };
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::operator()>*, int);
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::template operator()<T, I>>*, long);
template<typename U>
static std::false_type Test(...);
public:
static constexpr bool kExists = decltype(Test<Fn>(nullptr, 0))::value;
};
一些观察,没有特别的顺序...
您可以使用
std::true_type
和std::false_type
,而不是Exist
和NotExist
;因此kExists
初始化得到简化,不再需要std::is_same
。第二个模板参数调用
SFINAESimple
的正确语法是没有括号。我的意思是:&U::operator()
,不是&(U::operator())
您的
Test()
函数,将模板参数&U::operator()
传递给SFINAESimple
,适用于 non-template 函数;如果你希望它也适用于模板函数,你必须从可能的函数集中生成所需的函数,所以我添加了另一个传递&U::template operator()<T, I>
参数的Test()
函数鉴于 class 可以同时具有模板和 non-template 函数,编译器 select 两个
Test()
函数返回std::true
并给出一个错误,因为它不知道哪个更喜欢;为了允许编译器更喜欢一个版本或另一个版本,我添加了另一个参数(一个是int
,另一个是long
),因此调用Test<Fn>(nullptr, 0)
,编译器更喜欢int
版本(因为0
,第二个参数,是一个int
),避免歧义,避免错误。
下面是一个完整的编译示例
#include <iostream>
struct Simplified
{
// 1st operator - I need to detect its presence
template<typename T, int I>
void operator()(T & val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::to_string(I) << std::endl;
}
// 2nd operator
void operator()(double & val1, double val2)
{
std::cout << std::to_string(val1 + val2) << std::endl;
}
};
template<typename Fn, int I, typename T>
class TemplatedOperatorCheck
{
template<typename U, void(U::*)(T&, double)>
struct SFINAESimple
{ };
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::operator()>*, int);
template<typename U>
static std::true_type Test(SFINAESimple<U, &U::template operator()<T, I>>*, long);
template<typename U>
static std::false_type Test(...);
public:
static constexpr bool kExists = decltype(Test<Fn>(nullptr, 0))::value;
};
int main()
{
auto DoubleOpValid = TemplatedOperatorCheck<Simplified, 0, double>::kExists;
auto IntOpValid = TemplatedOperatorCheck<Simplified, 0, int>::kExists;
std::cout << DoubleOpValid << ' ' << IntOpValid << '\n';
}