【发布时间】:2018-01-04 13:43:59
【问题描述】:
首先是冗长的解释,其次是实际问题:
在 C++ 库中,我想提供自定义点。也就是说,某些方法可以由用户“注入”。通常,这是通过 ADL 以下列方式完成的:
文件operators.h 包含:
namespace operators
{
namespace print_overloads
{
void print_value(double x)
{
cout << x << endl;
}
}
namespace detail
{
template <typename Value>
void adl_print(Value x)
{
using print_overloads::print_value;
print_value(x);
}
}
template <typename Value>
void print(Value x)
{
detail::adl_print(x);
}
}
print_value() 通过 ADL 提供自定义点。要使用它,可能有testi.cpp:
#include "operator.h"
namespace custom
{
struct A {};
void print_value(A)
{
cout << "ADL A overload" << endl;
}
}
int main()
{
operators::print(custom::A{});
}
这按预期工作。但是,只有当用户可以在相应的命名空间(本例中为namespace custom)中定义函数时才适用。
我的想法是在上面的示例中引入一个专用的重载命名空间namespace print_overload。对于用户来说,这应该允许:
#include "operators.h"
namespace custom_inaccessible
{
struct A {};
}
namespace operators::print_overloads
{
void print_value(custom_inaccessible::A)
{
cout << "A overload" << endl;
}
}
int main()
{
operators::print(custom_inaccessible::A{});
int pause;
std::cin >> pause;
return 0;
}
很遗憾,这不起作用。当前的 Microsoft Visual Studio 2017 C++ 编译器失败:
error C2664: 'void operators::print_overloads::print_value(double)': cannot convert argument 1 from 'testi::B' to 'double'
似乎print_value(A) 的重载不在重载列表中考虑。经过一番修改,我发现一致性模式设置设置为Yes(/permissive-)。如果我将其设置为 No 一切正常。
现在回答问题:
- 标准中是否定义了这种行为?
- 如果是这样,该标准的哪一部分对这个结果负责?
- 还是 Visual Studio 一致性模式的一些错误?
【问题讨论】:
-
在coliru.stacked-crooked.com 上尝试使用 gcc 和 clang 的代码。但看起来一致性模式设置具有正确的行为,而非一致性模式不正确,因为在解析函数调用时,只考虑先前声明的函数,直到最近 MSVC 对模板出错。
-
我会说使用 ADL 来做这件事是相当不寻常的。最好引入一些可以由用户专门化的类型特征或接受一些具有默认值的额外模板参数。
-
@VTT 我指的是这个:ericniebler.com/2014/10/21/…
标签: c++ visual-studio-2017 overloading