当方法可用时,我如何专门化模板?

How I can specialize template when a method is available?

我想知道当我的类型具有特定方法时,我如何才能拥有专门的模板。我们以下面的代码为例:

template<typename T, typename... Args>
void foo(T&& arg, Args&&... args) 
{
    std::cout << "called 1\n";
}

template<typename T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::log)>, int> = 0>
void foo(T&& v)
{
    v.log();
}

struct Y
{
    void log() const 
    {
        std::cout << "called 2\n";
    }
};

int main()
{
    foo(1); // <-- print "called 1";
    Y y;
    foo(y); // <-- print "called 2";
}

我应该说这段代码不起作用(第二个 foo 将使用主模板并打印 called 1)而且我知道我不能部分特化函数调用,但它显示了我需要的.

知道如何实现这样的目标吗?我应该使用结构进行部分特化然后使用辅助函数吗?

你不需要那么冗长;您可以启用另一个 foo,方法如下:

template<typename T>
auto foo(T&& v) -> decltype(v.log(), void())  
{
    v.log();
}

(See a Demo)

这叫做trailing return type. You provide the decltype to evaluate the expressions (1. v.log(), 2. void()) with comma operator分离。如果第一个表达式(即 v.log())失败,则重载不适合调用。因此,它适用于另一个 foo。否则,它接受带有 void return 的重载,这是从 void() 表达式求值的!

你走的很好,但是,转发参考,

decltype(&T::log) 变为 decltype(&(Y&)::log) 无效。

使用 std::decay 解决了您的问题:

template<typename T, 
    std::enable_if_t<
        std::is_member_function_pointer_v<decltype(&std::decay_t<T>::log)>,
        int> = 0>
void foo(T&& v)
{
    v.log();
}

Demo