如何消除重载模板函数的歧义?
How to disambiguate overloaded template functions?
以下代码有问题。虽然第 1 部分没问题,但问题出在 main()
的第 2 部分。编译时,会显示一条不明确的错误消息。如何更改代码以解决歧义?
template<typename Arg> void func(Arg arg)
{
arg();
}
template<typename Arg, typename... Args> void func(Arg arg, Args... args)
{
func(args...);
arg();
}
template<typename Container> void func(Container & c)
{
for (typename Container::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
}
void f()
{
std::cout << "+" ;
}
int main()
{
//1
func(f,f,f);
//2
std::vector<std::function<void()> > v{f,f};
func(v);
}
Link 编码:http://cpp.sh/3wxrc
How can I change the code to resolve the ambiguity?
也许使用模板模板?
template <template <typename ...> class Cont, typename ... Ts>
void func (Cont<Ts...> & c)
{
for (typename Cont<Ts...>::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
}
删除基于 func()
Container
的版本,很明显。
简单地定义一个模板参数Container
,不要让它与通用Arg
模板参数不同。
我知道您在函数内部使用了 typename Cont<Ts...>::reverse_iterator
。但是编译器必须根据函数签名而不是函数体来选择正确的重载。
使用 Cont<Ts...>
参数,你有更专业的东西。
问题是它无法推断 func
调用第一个还是第三个。这就是您可以在不更改函数重载层次结构的情况下使其工作的方法,或者按照上一条评论中的回答进行操作
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
template<typename Arg>
void func(Arg* arg)
{
arg();
}
template<typename Arg, typename... Args>
void func(Arg arg, Args... args)
{
func(args...);
arg();
}
template<typename Container>
void func(Container&& c)
{
for (typename Container::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
//OR Which is bettere to use
/*for(auto && e : c){
e();
}*/
}
void f()
{
std::cout << "+" ;
}
int main()
{
//1
func(f,f,f);
//2
std::vector<std::function<void()> > v{f,f};
func(std::move(v));
}
如果你有 C++17,那么 std::enable_if_t
可以与 std::is_invocable_v
一起使用(这需要 C++17):
template<typename Arg>
std::enable_if_t<std::is_invocable_v<Arg>>
func(Arg arg)
{
arg();
}
我会首先从单个作业中拆分(可变)迭代:
// func overloads with one parameter.
template <typename ...Ts>
void funcs(Ts&&... args)
{
const int dummy[] = {(func(std::forward<Ts>(args)), 0)..., 0};
static_cast<void>(dummy); // Avoid warning for unused variable
// Or in C++17:
// (func(std::forward<Ts>(args)), ...);
}
那么对于只有一个参数的方法,任何左值引用都是不明确的,因为签名是:
template<typename Arg> void func(Arg arg);
template<typename Container> void func(Container & c);
您可以使用 SFINAE 来区分它们:
template<typename Arg>
auto func(Arg arg)
-> decltype(arg(), void())
{
arg();
}
template<typename Container>
auto func(Container& c)
-> decltype(c.rbegin() != c.rend(), (*c.rbegin())(), void())
{
for (auto it = c.rbegin(); it != c.rend(); ++it)
{
(*it)();
}
}
以下代码有问题。虽然第 1 部分没问题,但问题出在 main()
的第 2 部分。编译时,会显示一条不明确的错误消息。如何更改代码以解决歧义?
template<typename Arg> void func(Arg arg)
{
arg();
}
template<typename Arg, typename... Args> void func(Arg arg, Args... args)
{
func(args...);
arg();
}
template<typename Container> void func(Container & c)
{
for (typename Container::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
}
void f()
{
std::cout << "+" ;
}
int main()
{
//1
func(f,f,f);
//2
std::vector<std::function<void()> > v{f,f};
func(v);
}
Link 编码:http://cpp.sh/3wxrc
How can I change the code to resolve the ambiguity?
也许使用模板模板?
template <template <typename ...> class Cont, typename ... Ts>
void func (Cont<Ts...> & c)
{
for (typename Cont<Ts...>::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
}
删除基于 func()
Container
的版本,很明显。
简单地定义一个模板参数Container
,不要让它与通用Arg
模板参数不同。
我知道您在函数内部使用了 typename Cont<Ts...>::reverse_iterator
。但是编译器必须根据函数签名而不是函数体来选择正确的重载。
使用 Cont<Ts...>
参数,你有更专业的东西。
问题是它无法推断 func
调用第一个还是第三个。这就是您可以在不更改函数重载层次结构的情况下使其工作的方法,或者按照上一条评论中的回答进行操作
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
template<typename Arg>
void func(Arg* arg)
{
arg();
}
template<typename Arg, typename... Args>
void func(Arg arg, Args... args)
{
func(args...);
arg();
}
template<typename Container>
void func(Container&& c)
{
for (typename Container::reverse_iterator i = c.rbegin(); i != c.rend(); ++i )
{
(*i)();
}
//OR Which is bettere to use
/*for(auto && e : c){
e();
}*/
}
void f()
{
std::cout << "+" ;
}
int main()
{
//1
func(f,f,f);
//2
std::vector<std::function<void()> > v{f,f};
func(std::move(v));
}
如果你有 C++17,那么 std::enable_if_t
可以与 std::is_invocable_v
一起使用(这需要 C++17):
template<typename Arg>
std::enable_if_t<std::is_invocable_v<Arg>>
func(Arg arg)
{
arg();
}
我会首先从单个作业中拆分(可变)迭代:
// func overloads with one parameter.
template <typename ...Ts>
void funcs(Ts&&... args)
{
const int dummy[] = {(func(std::forward<Ts>(args)), 0)..., 0};
static_cast<void>(dummy); // Avoid warning for unused variable
// Or in C++17:
// (func(std::forward<Ts>(args)), ...);
}
那么对于只有一个参数的方法,任何左值引用都是不明确的,因为签名是:
template<typename Arg> void func(Arg arg);
template<typename Container> void func(Container & c);
您可以使用 SFINAE 来区分它们:
template<typename Arg>
auto func(Arg arg)
-> decltype(arg(), void())
{
arg();
}
template<typename Container>
auto func(Container& c)
-> decltype(c.rbegin() != c.rend(), (*c.rbegin())(), void())
{
for (auto it = c.rbegin(); it != c.rend(); ++it)
{
(*it)();
}
}