【问题标题】:How I can specialize template when a method is available?当方法可用时如何专门化模板?
【发布时间】:2021-10-15 03:06:37
【问题描述】:

我想知道当我的类型有一个特定的方法时,我怎么能有一个专门的模板。我们以下面的代码为例:

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),我知道我不能部分专门化函数调用,但它显示了我需要的东西。

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

【问题讨论】:

  • 顺便说一句,你没有专门化,但提供了重载。

标签: c++ templates c++17 sfinae function-templates


【解决方案1】:

您的进展顺利,但是,通过转发参考,

decltype(&amp;T::log) 变为 decltype(&amp;(Y&amp;)::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

【讨论】:

  • ouch.....我看不到问题,因为当我删除主模板时,即使没有衰减也会调用这个模板。我想知道为什么会这样。
【解决方案2】:

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

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

(See a Demo)

它被称为trailing return type。您提供 decltype 来评估表达式 (1. v.log(), 2. void()) 与 comma operator 分隔。如果第一个表达式(即v.log())失败,则重载不适合调用。因此,它适用于另一个foo。否则,它接受这个重载并返回 void,它是从 void() 表达式中计算出来的!

【讨论】:

  • 谢谢。什么是第二个?它不是专业化,是吗?为什么选择它而不是主模板?
  • 但是为什么要先测试呢?因为在我的代码的情况下,它根本没有被检查。我的第二个模板有效,但在我删除主模板之前不会对其进行检查。
  • @Afshin 对于函数调用foo(1);,哪个合适?带有三元参数的那个?还是单人?单参数对吗?因此,它会先检查一个,然后再检查另一个。
  • 啊哈,我明白你的意思了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多