c++ - 基于嵌套类型的模板函数选择

标签 c++ gcc visual-studio-2015 clang function-templates

以下代码在 VS2015 上可以正常工作:

struct Foo
{
   using Bar = int;
   auto operator()() { return "Foo!";  }
};

template <typename Callable, typename CodeType> // <<< CodeType is a template param
void funky(CodeType code, Callable func)
{
   cout << "Generic: " << code << ", " << func() << endl;
}

template <typename HasBar>
void funky(typename HasBar::Bar code, HasBar func) // <<< The code type is a nested type
{
   cout << "Has Bar: " << code << ", " << func() << endl;
}

int main()
{
   Foo foo;
   funky(3, []() { return "Lambda!"; });
   funky(3, foo);
   return 0;
}

打印:

Generic: 3, Lambda!
Has Bar: 3, Foo!

然而,it does not compile在 gcc/clang 上,提示:

 In function 'int main()':
27:16: error: call of overloaded 'funky(int, Foo&)' is ambiguous
27:16: note: candidates are:
12:6: note: void funky(CodeType, Callable) [with Callable = Foo; CodeType = int]
18:6: note: void funky(typename HasBar::Bar, HasBar) [with HasBar = Foo; typename HasBar::Bar = int]

歧义由 VS2015 正确解决(这并不意味着它是符合要求的事情)。

我怎样才能让它在 Clang/gcc 上正确编译和运行?
我想过使用 std::enable_if 但无法让它做我想做的事(我很可能使用不正确)。如果这是要走的路,应该如何使用它来解决这种歧义?

更新:
将 typename HasBar::Bar 添加到模板参数中可以让 gcc/Clang 正确构建和运行代码:

template <typename HasBar, typename HasBar::Bar>
void funky(typename HasBar::Bar code, HasBar func) // <<< The code type is a nested type
{
   cout << "Has Bar: " << code << ", " << func() << endl;
}

这似乎告诉编译器还有第二个非类型模板参数值(在函数代码中未使用),类型为 typename HasBar::Bar如果 typename HasBar::Bar 不存在,SFINAE 将从重载集中删除该函数,并选择泛型形式。

但是,当它确实存在时,我不知道为什么这个函数会优先于第一个。我猜是因为它更专业——尽管代码本身没有使用特化。 然而,在这种情况下,它甚至在新参数出现之前就已经更加特化了!

但是,在这种情况下,VS2015 总是选择给出错误答案的通用形式!

是否有一些语法(和/或解决方法)适用于所有情况?

最佳答案

13 分钟后...回答我自己。 [NOT] 已解决!

typename HasBar::Bar 添加到模板参数 did the trick :

template <typename HasBar, typename HasBar::Bar>
void funky(typename HasBar::Bar code, HasBar func) // <<< The code type is a nested type
{
   cout << "Has Bar: " << code << ", " << func() << endl;
}

这似乎告诉编译器还有第二个非类型模板参数值(在函数代码中未使用),类型为 typename HasBar::Bar。如果 typename HasBar::Bar 不存在,SFINAE 将从重载集中删除此函数,并选择通用形式。

但是,当它确实存在时,我不知道为什么这个函数会优先于第一个。我猜是因为它更特化——尽管代码本身没有使用特化。
然而,在这种情况下,它甚至在新参数出现之前就已经更加特化了!

关于c++ - 基于嵌套类型的模板函数选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37276525/

相关文章:

C++ 预编译 header 已禁用

c++ - 即使没有新数据,FD_ISSET 也始终为真?

c# - Microsoft.Lightswitch.Build.Tasks.Targets(168,5): application definition contains critical errors

visual-studio-2015 - Azure DevOps Build - 发布时不会在 bin 文件夹中创建 .compiled 文件

javascript - 在 Visual Studio 2015 + Node.js 中显示 JavaScript 文件的导航栏

c++ - 通过指向其基类的指针删除派生对象

C++ 格式化浮点自动精度

使用 gettext 时 gcc 可以检查 printf 格式吗?

xcode - 使用 CPP 定义构建 pch 文件时出错

c++ - 奇怪的 GCC 错误 : expected primary-expression before ',' token