После того, как у меня возникли проблемы с другим дизайном, я решил сделать класс-оболочку для добавления перегрузок к некоторым функциям-членам базового класса, если и только если жизнеспособные перегрузки еще не существуют в базовом классе. В основном, вот что я пытаюсь сделать:
template<typename T>
struct wrapper: T
{
using T::foo;
template<typename Arg>
auto foo(Arg) const
-> std::enable_if_t<not std::is_constructible<Arg>::value, bool>
{
return false;
}
};
struct bar
{
template<typename Arg>
auto foo(Arg) const
-> bool
{
return true;
}
};
В этом простом примере wrapper
добавляет перегруженный foo
только в том случае, если один из базового класса не является жизнеспособным (я упростил std::enable_if
к простейшей возможной вещи, в оригинальной - идиоме обнаружения). Однако g++ и clang++ не согласны. Возьмите следующий main
:
int main()
{
assert(wrapper<bar>{}.foo(0));
}
g++ в порядке: foo
from wrapper<bar>
является SFINAEd, поэтому вместо него он использует один из bar
. С другой стороны, clang++, похоже, предполагает, что wrapper<bar>::foo
всегда тени bar::foo
, даже когда SFINAEd выйдет. Вот сообщение об ошибке:
main.cpp:30:26: error: no matching member function for call to 'foo' assert(wrapper<bar>{}.foo(0)); ~~~~~~~~~~~~~~~^~~ /usr/include/assert.h:92:5: note: expanded from macro 'assert' ((expr) \ ^ /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with Arg = int] using enable_if_t = typename enable_if<_Cond, _Tp>::type; ^ 1 error generated.
Итак, кто прав? Должен ли этот код отклоняться так же, как и clang++, или он должен работать и вызывать bar::foo
?