关于SO的一些问题是将函数指针作为参数/参数(here,here,here等)进行处理。事实上,前几天我问related question。但是,这个问题有点不同。
我的问题是我正在写一篇我非常灵活的课程。
我现在拥有的非会员功能。它发布在
下面template <typename T>
class MyClass
{
private:
typedef double (*firstFunctionPtr) (const T &var);
typedef bool (*secondFunctionPtr)(const T &var);
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc,
secondFunctionPtr secondFunc);
};
template<typename T>
MyClass<T>::MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc),
{}
然而,当我需要使用指向某个其他任意类的成员函数的指针进行初始化时,这种情况就会崩溃,不幸的是,这对于我来说恰好是一个常见的用例。
在适当的C ++接口中,您可能希望查看函数对函数对象使用模板化参数来使用任意类类型。
但是,我无法进行此编译。我试过模板化我的typedef(使用C ++ 11别名方法),我尝试在类中添加第二个模板参数来处理这些成员函数的调用类,但这两种方法都没有用。
This Q/A似乎正朝着我正在努力的方向前进,但我无法做出正面或反面。
为了记录,我试图避免使用functional
标题,但是不使用它可能是个傻瓜。
答案 0 :(得分:2)
如果您希望MyClass
成为可以同时保存两个免费功能的模板
类型指针:
double (*)(const T &var);
bool (*)(const T &var);
用于某些参数类型T
,或者成员函数
类型指针:
double (C::*)(const T &var);
bool (C::*)(const T &var);
对于某些参数类型C
和T
,必须参数化MyClass
T
和C
同时需要两个专业化:
C
是某类非类型C
是任何班级类型在情况(1)中,非类型C
不可能具有成员函数,
这样就可以实现自由函数指针的专门化。
在情况(2)中,类C
可以是具有成员函数的类,因此可以是一个
将实现成员函数指针特化。
非类型C
的明显选择是void
。所以我们可以C
默认为void
:
主要模板
template<typename T, typename C = void>
struct MyClass;
那样:
MyClass<T>
将是T
的自由函数指针特化,并且:
MyClass<T,C>
对于除C
以外的任何void
,将是成员函数指针特化。
您可能知道可以使用std::enable_if
和SFINAE
来制作编译器
选择一个或多个类模板的一个专门化,取决于是否一个
其模板参数U
满足一些编译时测试。你可以拿走
这种方法,但另一个可用,不需要该设备:
从主模板开始,我们只想:
自由职能专业化
template<typename T>
struct MyClass<T>
{
... for free function pointers ...
};
和
会员功能专业化
template<typename T, typename C>
struct MyClass<T,C>
{
... for member function pointers ...
};
但我们不能做到这一点,因为会员功能&#34;专业化&#34;确切地说 与主模板相同的模板参数。这意味着不是 专业化,编译器不允许它。
但是,您可以轻松地删除该问题,只需提供主要问题即可 模板一个它不需要的默认模板参数,但是它的 存在允许这两个专业化站立。
新的主要模板
template <typename T, typename C = void, typename Default = void>
struct MyClass;
所以这是一个说明性的解决方案:
// Primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
// Free function specialization
template <typename T>
struct MyClass<T>
{
using firstFunctor_t = double(*)(T const &);
using secondFunctor_t = bool(*)(T const &);
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(T const & var) {
return _firstFunc(var);
}
bool callSecond(T const & var) {
return _secondFunc(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
// Member function specialization
template <typename T, typename C>
struct MyClass<T,C>
{
using firstFunctor_t = double(C::*)(T const &);
using secondFunctor_t = bool(C::*)(T const &) const;
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(C & obj, T const & var) {
return (obj.*_firstFunc)(var);
}
double callFirst(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_firstFunc)(var);
}
bool callSecond(C & obj, T const & var) {
return (obj.*_secondFunc)(var);
}
bool callSecond(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_secondFunc)(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
在成员函数专业化中,请注意您可能会提出的几点 没有考虑过: -
我决定要存储的第二个成员函数是a
const 成员函数。它很可能是C
的成员函数
采用T const &
参数并返回bool将是const
成员
功能,不是吗?如果是这样,则const-ness
必须成为其中的一部分
我在专业化中使用的成员函数类型定义:
using secondFunctor_t = bool(C::*)(T const &) const;
或尝试使用任何bool (C::*)(T const &) const
实例化专业化
将无法编译。
另外,我为每个MyClass<T,C>::callFirst
提供了两个重载
和MyClass<T,C>::callSecond
,一个有参数:
C & obj, T const & var
和另一个有参数:
C const & obj, T const & var
没有秒,尝试调用MyClass<T,C>::callFirst
或者MyClass<T,C>::callSecond
与obj
是const将失败
编译。
对于演示此解决方案的程序,您可以附加:
#include <iostream>
#include <string>
double foo(std::string const & s)
{
return std::stod(s);
}
bool bar(std::string const & s)
{
return s.size() > 0;
}
struct SomeClass
{
SomeClass(){};
double foo(std::string const & s) {
return ::foo(s);
}
bool bar(std::string const & s) const {
return ::bar(s);
}
};
int main()
{
MyClass<std::string> my0{foo,bar};
std::cout << std::boolalpha;
std::cout << my0.callFirst("1.11") << std::endl;
std::cout << my0.callSecond("Hello World") << std::endl;
MyClass<std::string,SomeClass> my1{&SomeClass::foo,&SomeClass::bar};
SomeClass thing;
std::cout << my1.callFirst(thing,"2.22") << std::endl;
std::cout << my1.callSecond(thing,"Hello World") << std::endl;
SomeClass const constThing;
std::cout << my1.callFirst(constThing,"3.33") << std::endl;
std::cout << my1.callSecond(constThing,"Hello World") << std::endl;
return 0;
}
你说你希望这个模板非常灵活&#34;。该 说明的解决方案适用于您的示例,但您可能是 有兴趣知道它并不像你能得到的那样灵活。 对于免费功能和成员功能,附加variadic template 参数,您的模板可以存储和调用[成员]函数 任意类型的仲裁返回类型和任意类型的仲裁数。 见this question和 答案。
答案 1 :(得分:1)
我将sugest创建一个帮助对象,它将存储您要使用的类型:
template <typename RETURN, typename TYPE, typename CLASS>
struct function_pointer
{ using type_t = RETURN (CLASS::*)(const TYPE &); };
template <typename RETURN, typename TYPE>
struct function_pointer<RETURN, TYPE, std::nullptr_t>
{ using type_t = RETURN (*)(const TYPE &); };
如果提供类作为第三个参数,则此类型将创建成员函数指针,否则创建函数指针。现在,我们可以在MyClass
中使用此帮助程序:
template <typename T, typename CLASS = std::nullptr_t>
class MyClass
{
using firstFunctionPtr = typename function_pointer<double, T, CLASS>::type_t;
using secondFunctionPtr = typename function_pointer<bool, T, CLASS>::type_t;
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
void call_first(CLASS &c, const T&v) { (c.*_firstFunc)(v); }
void call_second(CLASS &c, const T&v) { (c.*_secondFunc)(v); }
void call_first(const T&v) { (_firstFunc)(v); }
void call_second(const T&v) { (_secondFunc)(v); }
};
我添加了call_*
函数只是为了显示一个用例,如下所示:
// Some class with the expected function signatures
struct S1
{
int i = 0;
double d(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Another class with the expected function signatures
struct S2
{
double d(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Free function with which could have the expected function signature
template <typename R>
R f(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
将MyClass
与任意类(S1
)一起使用:
S1 a{1}, b{2};
S2 c, d;
MyClass<int, S1> MCiS1(&S1::d, &S1::b);
MCiS1.call_first(a, 111); // Prints -> 1 double S1::d(const int&)
MCiS1.call_second(b, 222); // Prints -> 2 bool S1::b(const int&)
MCiS1.call_first(c, 111); // Error decltype(c) is not S1.
MCiS1.call_second(d, 222); // Error decltype(d) is not S1.
将MyClass
与其他类(S2
)一起使用:
MyClass<int, S2> MCiS2(&S2::d, &S2::b);
MCiS2.call_first(c, 111); // Prints -> double S2::d(const int&)
MCiS2.call_second(d, 222); // Prints -> bool S2::b(const int&)
MCiS2.call_first(a, 111); // Error decltype(c) is not S2.
MCiS2.call_second(b, 222); // Error decltype(d) is not S2.
将MyClass
与非成员函数一起使用:
MyClass<int> MCi(f<double>, f<bool>);
MCi.call_first(111); // Prints -> R f(const int&) [with R = double]
MCi.call_second(222); // Prints -> R f(const int&) [with R = bool]
查看现场演示 Here 。
答案 2 :(得分:0)
您需要做的就是将bind
成员函数指针的对象实例作为第一个参数。
struct foo {
float bar1(const type &var);
bool bar2(const type &var);
};
foo my_foo;
auto f1 = std::bind(&foo::bar1, my_foo, _1);
auto f2 = std::bind(&foo::bar2, my_foo, _1);
MyClass<type> my_obj(f1, f2);