C ++无效的引用问题

时间:2010-03-27 08:14:39

标签: c++ reference initialization callback function-pointers

我正在用C ++编写一些回调实现。

我有一个抽象的回调类,让我们说:

/** Abstract callback class. */
class callback {
public:

    /** Executes the callback. */
    void call() { do_call(); };
protected:

    /** Callback call implementation specific to derived callback. */
    virtual void do_call() = 0;
};

我创建的每个回调(接受单参数函数,双参数函数......)都是使用以下之一创建的mixin:

/** Makes the callback a single-argument callback. */
template <typename T>
class singleArgumentCallback {
protected:
    /** Callback argument. */
    T arg;

public:
    /** Constructor. */
    singleArgumentCallback(T arg): arg(arg) { }
};

/** Makes the callback a double-argument callback. */
template <typename T, typename V>
class doubleArgumentCallback {
protected:
    /** Callback argument 1. */
    T arg1;

    /** Callback argument 2. */
    V arg2;

public:
    /** Constructor. */
    doubleArgumentCallback(T arg1, V arg2): arg1(arg1), arg2(arg2) { }
};

例如,单arg函数回调将如下所示:

/** Single-arg callbacks. */
template <typename T>
class singleArgFunctionCallback:
    public callback,
    protected singleArgumentCallback<T> {

    /** Callback. */
    void (*callbackMethod)(T arg);

public:
   /** Constructor. */
    singleArgFunctionCallback(void (*callback)(T), T argument):
        singleArgumentCallback<T>(argument),
        callbackMethod(callback) { }

protected:
    void do_call() {
        this->callbackMethod(this->arg);
    }
};

为了方便用户,我希望有一个方法可以在不让用户考虑细节的情况下创建回调,以便可以调用(不幸的是,此接口不会发生变化):

void test3(float x) { std::cout << x << std::endl; }
void test5(const std::string& s) { std::cout << s << std::endl; }

make_callback(&test3, 12.0f)->call();
make_callback(&test5, "oh hai!")->call();

我目前对make_callback(...)的实施如下:

/** Creates a callback object. */
template <typename T, typename U> callback* make_callback(
    void (*callbackMethod)(T), U argument) {
    return new singleArgFunctionCallback<T>(callbackMethod, argument);
}

不幸的是,当我调用make_callback(&test5, "oh hai!")->call();时,我在标准输出上得到一个空字符串。我认为问题是在回调初始化之后引用超出了范围。

我尝试使用指针和引用,但是引用指针/引用是不可能的,所以我失败了。我唯一的解决方案是禁止将引用类型替换为T(例如,T不能是std :: string&amp;),但这是一个令人遗憾的解决方案,因为我必须创建另一个singleArgCallbackAcceptingReference类,接受具有以下签名的函数指针:

void (*callbackMethod)(T& arg);

因此,我的代码重复了2 ^ n次,其中n是回调函数的参数个数。

有人知道任何解决方法或有任何想法如何修复它?提前谢谢!

3 个答案:

答案 0 :(得分:3)

问题在于make_callback()T变为const std::string&,而T中的singleArgumentCallback变为U。但是,const char*std::string,因此会创建一个临时singleArgumentCallback对象并绑定到make_callback()中的该引用。当singleArgumentCallback完成时,该临时文件将被销毁,从而使创建的make_callback()对象具有对不再存在的对象的引用。

您需要做的是首先从传递到template< typename T > struct remove_ref { typedef T result_type; }; template< typename T > struct remove_ref<T&> { typedef T result_type; }; 的类型中删除引用(以及可能的cv限定符)。作为Marcelo suggestedBoost.TypeTraits可以帮助您完成此操作,但如果您愿意,可以自行烹饪:

make_callback()

然后将template <typename T, typename U> callback* make_callback(void (*callbackMethod)(T), U argument) { typedef typename remove_ref<T>::result_type arg_type; return new singleArgFunctionCallback<arg_type>(callbackMethod, argument); } 更改为:

{{1}}

答案 1 :(得分:0)

Boost.TypeTraits可能有所帮助。 add_reference将具体类型转换为引用类型,同时保留引用类型。

答案 2 :(得分:0)

感谢 sbi ,我得到了这些东西: - )

我最终得到的解决方案是:

template <typename T> struct removeRef     { typedef T resultType; };
template <typename T> struct removeRef<T&> { typedef T resultType; };

/** Single-arg callbacks. */
template <typename T, typename U>
class singleArgFunctionCallback:
    public callback,
    protected singleArgumentCallback<U> {

    /** Callback. */
    void (*callbackMethod)(T arg);

public:
    /** Constructor. */
    singleArgFunctionCallback(void (*callback)(T), U argument):
        singleArgumentCallback<U>(argument),
        callbackMethod(callback) { }

protected:
    void do_call() {
        this->callbackMethod(this->arg);
    }
};

template <typename T, typename U>
callback* make_callback(void (*callbackMethod)(T), U argument) {
    typedef T ArgumentType;
    typedef typename removeRef<T>::resultType StrippedArgumentType;
    return new singleArgFunctionCallback<ArgumentType, StrippedArgumentType>(callbackMethod, argument);
}

如果有人看到任何可能的改进,我会很乐意学习!

谢谢大家, 卡罗尔