如何在没有实例的情况下获取非静态方法的类型?

How to get the type of non-static method without instance?

我正在尝试用 C++ 创建一个模板函数,例如:

template<typename IteratorType>
double evaluate(const IteratorType &rBegin, const IteratorType &rEnd,
    double(*function)( const decltype( *IteratorType ) &rObject )) // error, typename not allowed
    // I'm unsure if I need to put the reference there, not part of the problem.
{
    // ...
} 
// not my actual code, just to show an example.

虽然这不起作用,因为我需要一个 class/struct 的实例来调用非静态方法, 我不能这样做,因为它在一个函数中。 谷歌搜索了一下后,我找到了这个解决方案:


double(*function)( const typename std::iterator_traits<IteratorType>::value_type &rObject )

尽管如您所见,这使用起来很笨拙(而且更改起来很痛苦),尤其是当您尝试创建多个重载时。这似乎也不适用于我的迭代器,所以过了一会儿我意识到:

double(*function)( const typename IteratorType::value_type &rObject)

将是最好的解决方案。

最后我意识到不能保证“IteratorType”将 value_type 定义为值的类型,指针是一回事。

我有什么方法可以逃脱

double(*function)( const decltype(*IteratorType) &robject)

?

Though as you can see this gets clumsy to use [...]

提供一些模板别名,可以减少笨拙!

template<typename IteratorType>
using ValueType = typename std::iterator_traits<IteratorType>::value_type;

template<typename IteratorType>
using FunctionPtr = double(*)(const ValueType<IteratorType> &);

template<typename IteratorType>
double evaluate(const IteratorType rBegin, const IteratorType rEnd,
    FunctionPtr<IteratorType> function)  // now you can simply this
{
    
}

首先你需要一个最简单的例子来说明你的问题。以下是我从您的评论中了解到的内容:

#include <iostream>
#include <vector>
#include <string>

struct MyClass /* final */
{
    static double member(std::string const& val) /* noexcept */
    {
        std::cout << "double MyClass::member(int val): " << val << "\n";
        return {}; // return appropriate results
    }
};

template<typename IteratorType>
void evaluate(IteratorType rBegin, const IteratorType rEnd,
 // WHAT??? other than:
 // double(*function)(const typename std::iterator_traits<IteratorType>::value_type &rObject )
{
    while (rBegin != rEnd)
    {
        function(*rBegin);
        ++rBegin;
    }
}

int main()
{
    std::vector<std::string> vec{ "1", "2", "3"};
    evaluate(vec.cbegin(), vec.cend(), &MyClass::member);
}

Though as you can see this gets clumsy to use [...]

除了,如果您的问题是使用std::iterator_traits,您还有以下两个选择。

  • 选项 - I

    喜欢@chtz 在评论中提到,使用 std::declval 获取迭代器的下划线类型如下:

    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
     double(*function)(
     std::remove_reference_t<decltype(*std::declval<IteratorType>())> const&))
     //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--> value_type == std::string 
    {
        // ... code 
    }
    
    

    提供一个辅助模板类型别名是个不错的主意:

    template<typename IteratorType>
    using ValueType = std::remove_reference_t<decltype(*std::declval<IteratorType>())>;
    
    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
       double(*function)(ValueType<IteratorType> const&))
       //                ^^^^^^^^^^^^^^^^^^^^^^^ value_type == std::string
    {
       // ... code
    }
    

    (See live demo)

  • 选项 - II

    rBegin,通过将 T& 转换为 T 使用 std::remove_reference_t.

    
    template<typename IteratorType>
    void evaluate(IteratorType rBegin, const IteratorType rEnd,
       double(*function)(std::remove_reference_t<decltype(*rBegin)> const&))
       //                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---> std::string
    {
       // ... code
    }
    
    

    (See live demo)