简体   繁体   English

从模板检查成员函数重载是否存在

[英]Checking member function overload existence from a template

Is it possible to check whether a class has a certain member function overload from within a template member function? 是否可以从模板成员函数中检查类是否具有某个成员函数重载?

The best similar problem I was able to find is this one: Is it possible to write a template to check for a function's existence? 我能找到的最好的类似问题就是这个问题: 是否可以编写模板来检查函数的存在? As I understand it, this doesn't apply in to the case of checking for overloads of functions. 据我了解,这不适用于检查功能过载的情况。

Here a simplified example of how this would be applied: 这是一个如何应用它的简化示例:

struct A;
struct B;

class C
{
public:
    template<typename T>
    void doSomething(std::string asdf)
    {
        T data_structure;

        /** some code */

        if(OVERLOAD_EXISTS(manipulateStruct, T))
        {
            manipulateStruct(data_structure);
        }

        /** some more code */
    }

private:
    void manipulateStruct(B& b) {/** some different code */};
}

My question would be if some standard way exists to make the following usage of the code work: 我的问题是,如果存在一些标准方法来使代码的以下用法工作:

int main(int argc, const char** argv)
{
    C object;
    object.doSomething<A>("hello");
    object.doSomething<B>("world");
    exit(0);
}

The only methods I could think of would be to simply create an emtpy overload of manipulateStruct for struct A . 我能想到的唯一方法是简单地为struct A创建一个manipulateStruct结构的emtpy重载。 Otherwise the manipulation method could of course also be put into the structs to be manipulated, which would make SFINAE an option. 否则,操纵方法当然也可以放入要操纵的结构中,这将使SFINAE成为一种选择。 Let's assume both of these to not be a possiblity here. 让我们假设这两个都不是可能的。

Is there any way to get code similar to the above one to work? 有没有办法让代码与上面的代码类似? Does something similar to OVERLOAD_EXISTS exist, to let the compiler know when to add the manipulateStruct part to the generated code? 是否存在类似于OVERLOAD_EXISTS东西,让编译器知道何时将manipulateStruct部分添加到生成的代码中? Or is there maybe some way clever way to make SFINAE work for this case? 或者是否有一些聪明的方法让SFINAE适用于这种情况?

Testing overload existence (C++11) 测试过载存在(C ++ 11)

Since C++11, you can use a mix of std::declval and decltype to test for the existence of a specific overload: 从C ++ 11开始,您可以使用std :: declvaldecltype的混合来测试特定重载的存在:

// If overload exists, gets its return type.
// Else compiler error
decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))

This can be used in a SFINAE construct: 这可以在SFINAE构造中使用:

class C {
public:
    // implementation skipped
private:
    // Declared inside class C to access its private member.
    // Enable is just a fake argument to do SFINAE in specializations.
    template<typename T, typename Enable=void>
    struct can_manipulate;
}

template<typename T, typename Enable>
struct C::can_manipulate : std::false_type {};

// Implemented outside class C, because a complete definition of C is needed for the declval.
template<typename T>
struct C::can_manipulate<T,std::void_t<decltype(std::declval<C&>().manipulateStruct(std::declval<T&>()))>> : std::true_type {};

Here I am ignoring the return type of the overload using std::void_t (C++17, but C++11 alternatives should be possible). 这里我使用std :: void_t忽略了重载的返回类型(C ++ 17,但C ++ 11的替代方案应该是可行的)。 If you want to check the return type, you can pass it to std::is_same or std::is_assignable . 如果要检查返回类型,可以将其传递给std :: is_samestd :: is_assignable

doSomething implementation doSomething实施

C++17 C ++ 17

This can be done with constexpr if : 这可以通过constexpr完成, 如果

template<typename T>
void doSomething(std::string asdf) {
    T data_structure;
    if constexpr (can_manipulate<T>::value) {
        manipulateStruct(data_structure);
    }
}

The if constexpr will make the compiler discards the statement-true if the condition evaluates to false. if constexpr条件的计算结果为false, if constexpr将使编译器丢弃该statement-true Without the constexpr , the compilation will require the function call inside the if to be valid in all cases. 如果没有constexpr ,编译将要求if的函数调用在所有情况下都有效。

Live demo (C++17 full code) 现场演示(C ++ 17完整代码)

C++11 C ++ 11

You can emulate the if constexpr behaviour with SFINAE: 您可以使用SFINAE模拟if constexpr行为:

class C {
    // previous implementation
private:
    template<typename T, typename Enable=void>
    struct manipulator;
}

template<typename T, typename Enable>
struct C::manipulator {
    static void call(C&, T&) {
        //no-op
    }
};

// can_manipulate can be inlined and removed from the code
template<typename T>
struct C::manipulator<T, typename std::enable_if<C::can_manipulate<T>::value>::type> {
    static void call(C& object, T& local) {
        object.manipulateStruct(local);
    }
};

Function body: 功能体:

template<typename T>
T doSomething()
{
    T data_structure;
    // replace if-constexpr:
    manipulator<T>::call(*this, data_structure);
}

Live demo (C++11 full code) 现场演示(C ++ 11完整代码)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM