未作为最后一个参数传递时的模板参数包扣除 [英] Template parameter pack deduction when not passed as last parameter

查看:54
本文介绍了未作为最后一个参数传递时的模板参数包扣除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#include <iostream>
#include <functional>

template<typename... Args>
void testfunc(const std::function<void (float, Args..., char)>& func)
{

}

int main(int argc, char* argv[])
{
    auto func = [](float, int, char) {};
    auto sfunc = static_cast<std::function<void (float, int, char)>>(func);
    testfunc<int>(sfunc);

    return 0;
}

我明确指定类型是因为( https://stackoverflow.com/a/40476083 ):

I specify the type explicitly because (https://stackoverflow.com/a/40476083):

当参数包没有出现在参数的最后声明,它是一个非推论上下文.非推论上下文意味着必须显式地指定模板参数.

When a parameter pack doesn't appear last in the parameter declaration, it is a non-deduced context. A non-deduced context means that the template arguments have to be given explicitly.

MSVC成功编译了它,而gcc和clang都拒绝了该代码:

MSVC successfully compiles it, while both gcc and clang reject the code:

source_file.cpp: In function ‘int main(int, char**)’:
source_file.cpp:14:24: error: no matching function for call to ‘testfunc(std::function<void(float, int, char)>&)’
     testfunc<int>(sfunc);
                        ^
source_file.cpp:5:6: note: candidate: template<class ... Args> void testfunc(const std::function<void(float, Args ..., char)>&)
 void testfunc(const std::function<void (float, Args..., char)>& func)
      ^
source_file.cpp:5:6: note:   template argument deduction/substitution failed:
source_file.cpp:14:24: note:   mismatched types ‘char’ and ‘int’
     testfunc<int>(sfunc);
                        ^
source_file.cpp:14:24: note:   ‘std::function<void(float, int, char)>’ is not derived from ‘const std::function<void(float, Args ..., char)>’

现在让我们稍作更改-让我们从本地 func 删除 int 参数,从而使模板参数包变为空:

Let's now make a slight change - let's remove the int argument from our local func, thereby causing the template argument pack to become empty:

#include <iostream>
#include <functional>

template<typename... Args>
void testfunc(const std::function<void (float, Args..., char)>& func)
{

}

int main(int argc, char* argv[])
{
    auto func = [](float, char) {};
    auto sfunc = static_cast<std::function<void (float, char)>>(func);
    testfunc<>(sfunc);

    return 0;
}

这一次,所有三个编译器都将代码视为错误.已通过 http://rextester.com/l/cpp_online_compiler_gcc 和本地Visual Studio安装进行了测试.

This time, all three compilers reject the code as incorrect. Tested with http://rextester.com/l/cpp_online_compiler_gcc and a local Visual Studio installation.

问题:

  1. 在第一种情况下谁是正确的?
  2. 如何达到理想的效果-即如何明确指定(可能为空)参数包?

推荐答案

我们可以阻止推论:

template<typename... Args>
void testfunc(const block_deduction<std::function<void (float, Args..., char)>>& func)

使用

template<class T>
struct tag_t{using type=T;};

template<class T>
using block_deduction=typename tag_t<T>::type;

现在是 Args ... 处于非推论上下文中.

and now Args... is in a non-deduced context.

您可以使用SFINAE进行更奇特的操作,并省略 char ,然后测试 char Args ... 的末尾,但是似乎太过分了.

You can do fancier things with SFINAE and omitting char then testing that char is at the end of the Args..., but that seems overkill.

当gcc和clang与MSVC意见不一致时,我会向甜甜圈下注,这是不对的.但是我没有标准地去证实这一点.

I will bet dollars to donuts that when gcc and clang disagree with MSVC, MSVC isn't right. But I have not standard delved to confirm that.

这篇关于未作为最后一个参数传递时的模板参数包扣除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆