如何消除重载的模板函数的歧义?

时间:2019-08-27 13:16:45

标签: c++ c++11 templates overloading variadic-templates

以下代码有问题。尽管第一部分可以,但问题出在main()的第二部分。编译时,显示模糊的错误消息。如何更改代码以解决歧义?

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);
}

链接到代码:http://cpp.sh/3wxrc

4 个答案:

答案 0 :(得分:2)

  

如何更改代码以解决歧义?

也许使用template-template吗?

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...>参数,您将获得更专业的体验。

答案 1 :(得分:2)

如果您有C ++ 17,则可以与POST一起使用std::enable_if_t(此要求C ++ 17):

std::is_invocable_v

https://wandbox.org/permlink/E2PoQdMv1pwXdMgO

答案 2 :(得分:1)

我将首先从单一工作中拆分(可变)迭代:

// 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)();
    } 
}

Demo

答案 3 :(得分:0)

问题是它无法推断哪个function GridTitle({ children, columnEnd, columnStart, muted, rowStart, rowEnd, title, }: Props) { const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); function expandMenu(event: React.MouseEvent<HTMLButtonElement>) { setAnchorEl(event.currentTarget); } function handleClose() { setAnchorEl(null); } return ( <StyledGridCell columnStart={columnStart} columnEnd={columnEnd} rowStart={rowStart} rowEnd={rowEnd} > <div>{React.Children.toArray(children)}</div> <StyledIconButton onClick={expandMenu}> // the button to be hidden <DropdownIcon /> </StyledIconButton> <Menu id="propperty-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose} > <MenuItem onClick={handleClose}>Edit</MenuItem> <MenuItem onClick={handleClose}>Reset</MenuItem> </Menu> </StyledGridCell> ); } export default GridTitle; 来调用第一个或第三个。这样一来,您就可以在不更改函数重载层次或按照上一个注释中的回答的方式进行操作的情况下

func
相关问题