0

我有以下smart_ptr课程。

template <typename T>
class smart_ptr
{
public:
    // ... removed other member functions for simplicity
    T* get() { return ptr; }

    template <typename... Args>
    decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
    {
        return (*get()).operator ()(args...);
    }

private:
    T* ptr;
};

但是,当我将smart_ptr类用于不带 的 T 类型时operator (),它无法编译(这是正确的)。

我想要的是std::enable_if仅在 T 具有operator (). 当我开始这样做时,它变得非常模糊和复杂,因为我正在考虑使用 SFINAE 来检测 T 是否有operator (),然后将它与它结合std::enable_if以获得我想要的。但是,我在创建能够检测可变参数模板operator ()的 SFINAE 时迷失了方向(即不是Is it possible to write a template to check for a function's exist?的副本)。

任何人都可以帮忙吗?或者给出另一个(也许更简单)的解决方案?

ps 它必须在 GCC 4.5.3 上工作。

编辑:为了完整起见,我已经用 GCC 4.5.3 的工作解决方案回答了我自己的问题。

4

2 回答 2

2

编辑:与原始答案完全不同,没有给出真正的解决方案。

此代码在使用 gcc 4.5.1 的 ideone 上编译。这是我能做的最好的。

#include <array>
#include <iostream>

using namespace std;

template<typename T>
struct has_property
{
    struct UnmentionableType { UnmentionableType() {} };

    //test if type has operator() (...)
    template<typename U, typename A1, typename A2, typename A3, typename A4, typename A5>
    static auto ftest(U* t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> decltype((*t)(a1, a2, a3, a4, a5), char(0));
    static std::array<char, 2> ftest(...);

public:
    static const bool value = sizeof(ftest((T*)0, UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType(), UnmentionableType())) == 1;
};

class c1
{
public:
    int operator() () {  return 0; }
};

class c2
{
public:
    void operator() (int) { }
};

class c3
{
public:
    template<typename... Args>
    void operator() (Args... a) { }
};

class c4
{
public:
    template<typename T>
    void operator() (T t) { }
};

int main()
{
    cout<<boolalpha<<has_property<c1>::value<<endl;
    cout<<boolalpha<<has_property<c2>::value<<endl;
    cout<<boolalpha<<has_property<c3>::value<<endl;
    cout<<boolalpha<<has_property<c4>::value<<endl;
}

输出:

false
false
true
false

笔记:

1)根据要求,它仅在可变参数模板化 operator() 上触发(嗯,几乎)

2)这不是一个“完美”的解决方案,但它应该足够好用于实际使用。

不幸的是 gcc 4.5.1 不能扩展参数包;我怀疑这可能对你有用:

template<typename U, typename... A>
static auto ftest(U* t, A... a) -> decltype((*t)(a...), char(0));

我仍然看不到一种方法来实际测试函数的真实可变性,而不是只传递 5 个(或更多)随机类型参数。

使用 with_enable if - 除了部分类专业化之外,我没有看到任何其他解决方案:

//non-specialized
template<typename T, typename E=void>
class container
{
    T* ptr;

public:
    T* get() { return ptr; }
};

//specialization for class with appropriate operator()
template<typename T>
class container<T, typename std::enable_if<has_property<T>::value, void>::type>
{
    T* ptr;

public:
    T* get() { return ptr; }

    template <typename... Args>
    decltype(T::template operator ()(Args()...)) operator ()(Args... args) const
    {
        return (*get()).operator ()(args...);
    }
};
于 2012-11-27T23:35:57.677 回答
1

最后,我找到了 GCC 4.5.3 的解决方法!

template <typename T>
class smart_ptr
{
public:
    // ... removed other member functions for simplicity
    T* get() const { return ptr; }

private:
    template <typename... Args>
    struct opparen_constret
    {
        typedef decltype(std::declval<T const>()(std::declval<Args>()...)) type;
    };

    template <typename... Args>
    struct opparen_ret
    {
        typedef decltype(std::declval<T>()(std::declval<Args>()...)) type;
    };

public:
    template <typename... Args>
    typename opparen_constret<Args...>::type operator ()(Args... args) const
    {
        return (*get())(args...);
    }

    template <typename... Args>
    typename opparen_ret<Args...>::type operator ()(Args... args)
    {
        return (*get())(args...);
    }

private:
    T* ptr;
};
于 2012-11-28T01:48:31.860 回答