SFINAE: checking the existence of a function breaks when the overload is moved to other namespaces(SFINAE:当重载移动到其他命名空间时,检查函数是否存在中断)
问题描述
我想使用 SFINAE 检查特定命名空间中是否存在函数.我发现 SFINAE 可以测试来自另一个命名空间的免费函数 可以完成这项工作,但有些事情我不明白.
I want to check for the existence of a function in a specific namespace using SFINAE. I have found SFINAE to test a free function from another namespace which does the job, but there are some things I don't understand.
目前我有这个工作代码,直接来自链接的问题:
Currently I have this working code, straight from the linked question:
// switch to 0 to test the other case
#define ENABLE_FOO_BAR 1
namespace foo {
#if ENABLE_FOO_BAR
int bar();
#endif
}
namespace detail_overload {
template<typename... Args> void bar(Args&&...);
}
namespace detail {
using namespace detail_overload;
using namespace foo;
template<typename T> decltype(bar()) test(T);
template<typename> void test(...);
}
static constexpr bool has_foo_bar = std::is_same<decltype(detail::test<int>(0)), int>::value;
static_assert(has_foo_bar == ENABLE_FOO_BAR, "something went wrong");
(ENABLE_FOO_BAR
宏仅用于测试目的,在我的真实代码中我没有这样的宏,否则我不会使用 SFINAE)
(the ENABLE_FOO_BAR
macro is just for testing purpose, in my real code I don't have such a macro available otherwise I wouldn't be using SFINAE)
但是,只要我将 detail_overload::bar()
放入任何其他命名空间(根据需要调整 using
指令),检测就会静默中断,static_assert
在 foo::bar()
存在时 启动.它仅在虚拟" bar()
重载直接位于全局命名空间或 ::detail_overload
命名空间的一部分时才有效(注意全局 ::
范围).
However, as soon as I put detail_overload::bar()
in any other namespace (adjusting the using
directive as needed), the detection breaks silently and the static_assert
kicks in when foo::bar()
exists. It only works when the "dummy" bar()
overload is directly in the global namespace, or part of the ::detail_overload
namespace (note the global ::
scope).
// breaks
namespace feature_test {
namespace detail_overload {
template<typename... Args> void bar(Args&&...);
}
namespace detail {
using namespace detail_overload;
using namespace foo;
//...
// breaks
namespace feature_test {
template<typename... Args> void bar(Args&&...);
namespace detail {
using namespace foo;
//...
// breaks
namespace detail {
namespace detail_overload {
template<typename... Args> void bar(Args&&...);
}
using namespace detail_overload;
using namespace foo;
//...
// works
template<typename... Args> void bar(Args&&...);
namespace feature_test {
namespace detail {
using namespace foo;
//...
// works
namespace detail_overload {
template<typename... Args> void bar(Args&&...);
}
namespace feature_test {
namespace detail {
using namespace detail_overload;
using namespace foo;
//...
我意识到这与我链接到的问题完全相同,并且如前所述,我已经有了一个可行的解决方案,但是没有解决的是 为什么精确地会发生这种情况?
I realize this is the very same problem as the question I linked to, and as mentioned I already have a working solution, but what is not addressed there is why precisely does this happen?
作为一个附带问题,有没有什么方法可以实现正确的 SFINAE 检测而不用 bar()
或 detail_overload
命名空间污染全局命名空间?正如您可以从非工作示例中猜到的那样,我想将所有内容整齐地包装在单个 feature_test
命名空间中.
As a side question, is there any way to achieve correct SFINAE detection without polluting the global namespace with either bar()
or a detail_overload
namespace? As you can guess from the non-working examples, I'd like to neatly wrap everything in a single feature_test
namespace.
推荐答案
我会稍微改变一下,所以 bar
的后备声明不是模板(= 更短的代码),并且不要使用 SFINAE,因为这纯粹是一个名称查找问题.
I'll change it slightly so the fall-back declaration of bar
isn't a template (= shorter code), and don't use SFINAE as this is purely a name lookup issue.
namespace foo {
int bar(int);
}
namespace feature_test {
namespace detail_overload {
void bar(...);
}
namespace detail {
using namespace detail_overload;
using namespace foo;
void test() { bar(0); } // (A)
}
}
在 (A) 行中,编译器需要找到名称 bar
.它是如何查找的?它不依赖于参数,所以它必须是非限定查找:[basic.lookup.unqual]/2
In line (A), the compiler needs to find the name bar
. How is it looked up? It's not argument-dependent, so it must be unqualified lookup: [basic.lookup.unqual]/2
由 using-directive 指定的命名空间中的声明在包含 using-directive 的命名空间中变得可见;见 7.3.4.出于 3.4.1 中描述的非限定名称查找规则的目的,由 using-directive 指定的命名空间中的声明被视为该封闭命名空间的成员.
The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
注意它们变成了一个封闭的命名空间,而不是封闭的命名空间.[namespace.udir]/2 的详细信息揭示了这个问题:
Note they become in an enclosing namespace, not the enclosing namespace. The details from [namespace.udir]/2 reveal the issue:
[...] 在非限定名称查找 (3.4.1) 期间,名称看起来好像它们是在最近的封闭命名空间中声明的,该命名空间包含 using-directive 和指定的命名空间.
[...] During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
即对于test
里面的bar
的名称查找:
That is, for the name lookup of bar
inside test
:
namespace foo {
int bar(int);
}
// as if
using foo::bar;
namespace feature_test {
namespace detail_overload {
void bar(...);
}
// as if
using detail_overload::bar;
namespace detail {
// resolved
// using namespace detail_overload;
// using namespace foo;
void test() { bar(0); } // (A)
}
}
因此,在 feature_test
中找到的名称 bar
隐藏了在全局范围内找到的名称(不是).
Therefore, the name bar
found in feature_test
hides the name (not) found in the global scope.
注意:也许您可以通过依赖参数的名称查找(以及第二个 SFINAE)来解决这个问题.如果有什么想到的,我会补充的.
Note: Maybe you can hack around this issue with argument-dependent name lookup (and a second SFINAE). If something comes to my mind, I'll add it.
这篇关于SFINAE:当重载移动到其他命名空间时,检查函数是否存在中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:SFINAE:当重载移动到其他命名空间时,检查函数是否存在中断
基础教程推荐
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01