问题描述
我想使用SFINAE检查特定命名空间中是否存在函数。我找到了 SFINAE来测试另一个命名空间的自由函数
目前我有这个工作代码,直接从链接的问题:
这是工作,但有一些事情我不明白。//切换到0以测试其他情况
#define ENABLE_FOO_BAR 1
namespace foo {
#if ENABLE_FOO_BAR
int bar();
#endif
}
namespace detail_overload {
template< typename ... Args> void bar(Args& ...);
}
命名空间detail {
使用命名空间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>
static_assert(has_foo_bar == ENABLE_FOO_BAR,有问题);
( ENABLE_FOO_BAR 宏仅用于测试在我的实际代码中,我没有这样的宏,否则我不会使用SFINAE)
但是,一旦我在任何其他命名空间中放置 detail_overload :: bar()(根据需要调整使用指令) ),当 foo :: bar()存在 时,检测将静默断开, static_assert 强>。它只有当dummy bar() overload直接在全局命名空间中,或者是 :: detail_overload 命名空间(注意全局 :: scope)。
/ breaks
namespace feature_test {
namespace detail_overload {
template< typename ... Args> void bar(Args& ...);
}
命名空间detail {
使用命名空间detail_overload;
using namespace foo;
// ...
//断点
命名空间feature_test {
template< typename ... Args> void bar(Args& ...);
namespace detail {
using namespace foo;
// ...
//断点
命名空间详细信息{
namespace detail_overload {
template< typename ... Args> void bar(Args& ...);
}
使用命名空间detail_overload;
using namespace foo;
// ...
//工作
模板< typename ... Args> void bar(Args& ...);
namespace feature_test {
namespace detail {
using namespace foo;
// ...
//工作
命名空间detail_overload {
template< typename ... Args> void bar(Args& ...);
}
命名空间feature_test {
命名空间detail {
使用命名空间detail_overload;
using namespace foo;
// ...
我意识到这是和问题一样的问题链接到,如前所述,我已经有一个有效的解决方案,但是没有解决的是为什么确切是否会发生这种情况?
另一个问题是,有没有办法实现正确的SFINAE检测,而不污染全局命名空间 bar()或 detail_overload 命名空间?正如你可以从非工作示例中猜到的,我想整理一个 feature_test 命名空间。
namespace foo {
int bar int);
}
命名空间feature_test {
namespace detail_overload {
void bar(...);
}
命名空间详细信息{
using namespace detail_overload;
using namespace foo;
void test(){bar(0); } //(A)
}
}
,编译器需要找到 bar 的名称。如何查找?它不依赖于参数,所以它必须是无限查找:[basic.lookup.unqual] / 2
请注意,它们位于包含命名空间, 包含命名空间。来自[namespace.udir] / 2的细节揭示了问题:
也就是说,对 bar 里面的测试的名称查找:
namespace foo {
int bar(int);
}
//如果
使用foo :: bar;
namespace feature_test {
namespace detail_overload {
void bar(...);
}
//如果
使用detail_overload :: bar;
namespace detail {
//解决
//使用命名空间detail_overload;
// using namespace foo;
void test(){bar(0); } //(A)
}
}
code> bar 在中找到feature_test 隐藏在全局范围中找到的名称(not)。
注意:也许你可以通过参数相关的名称查找(和另一个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");
(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)
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?
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.
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) } }
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
Note they become in an enclosing namespace, not the enclosing namespace. The details from [namespace.udir]/2 reveal the issue:
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) } }
Therefore, the name bar found in feature_test hides the name (not) found in the global scope.
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:当重载被移动到其他命名空间时,检查函数的存在会中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!