В качестве продолжения мой предыдущий вопрос, Я пытаюсь обнаружить существование шаблонной функции, которая требует явной специализации.
Мой текущий рабочий код обнаруживает не шаблонные функции (благодаря помощи DyP), при условии, что они принимают хотя бы один параметр, чтобы можно было использовать поиск зависимых имен:
// switch to 0 to test the other case
#define ENABLE_FOO_BAR 1
namespace foo {
#if ENABLE_FOO_BAR
int bar(int);
#endif
}
namespace feature_test {
namespace detail {
using namespace foo;
template<typename T> decltype(bar(std::declval<T>())) test(int);
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)
Это также прекрасно работает с шаблонными функциями, когда их аргументы шаблона могут автоматически выводиться компилятором:
namespace foo {
#if ENABLE_FOO_BAR
template<typename T> int bar(T);
#endif
}
Однако, когда я пытаюсь обнаружить шаблонную функцию, которая требует явной специализации, static_assert
удары в когда foo::bar()
существует:
namespace foo {
#if ENABLE_FOO_BAR
template<typename T, typename U> T bar(U);
#endif
}
//...
// error: static assertion failed: something went wrong
Очевидно, что компилятор не может вывести аргументы шаблона bar()
поэтому обнаружение не удается. Я попытался исправить это, явно специализируя вызов:
template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
// explicit specialization ^^^^^^^^
Это прекрасно работает, когда foo::bar()
существует (функция правильно определена), но теперь все черты когда foo::bar()
не существует:
error: ‘bar’ was not declared in this scope
template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
^
error: expected primary-expression before ‘int’
template<typename T> decltype(bar<int, T>(std::declval<T>())) test(int);
^
// lots of meaningless errors that derive from the first two
Кажется, моя попытка явной специализации провалилась, потому что компилятор не знает, что bar
это шаблон.
Я избавлю вас от всего, что я пытался исправить, и сразу перейду к делу: как я могу обнаружить существование такой функции, как template<typename T, typename U> T bar(U);
что требует явной специализации, чтобы быть реализованным?
Следующее может помочь вам:
// Helper macro to create traits to check if function exist.
// Note: template funcName should exist, see below for a work around.
#define HAS_TEMPLATED_FUNC(traitsName, funcName, Prototype) \
template<typename U> \
class traitsName \
{ \
typedef std::uint8_t yes; \
typedef std::uint16_t no; \
template <typename T, T> struct type_check; \
template <typename T = U> static yes &chk(type_check<Prototype, &funcName>*); \
template <typename > static no &chk(...); \
public: \
static bool const value = sizeof(chk<U>(0)) == sizeof(yes); \
}
Так с предоставленным пространством имен с bar
и без bar2
// namespace to test
namespace foo {
template<typename T, typename U> T bar(U);
// bar2 not present
}
Код, который проверяет наличие bar<int, int>
а также bar2<int, int>
,
// dummy class which should be never used
namespace detail {
struct dummy;
}
// Trick, so the names exist.
// we use a specialization which should never happen
namespace foo {
template <typename T, typename U>
std::enable_if<std::is_same<detail::dummy, T>::value, T> bar(U);
template <typename T, typename U>
std::enable_if<std::is_same<detail::dummy, T>::value, T> bar2(U);
}
#define COMMA_ , // trick to be able to use ',' in macro
// Create the traits
HAS_TEMPLATED_FUNC(has_foo_bar, foo::bar<T COMMA_ int>, int(*)(int));
HAS_TEMPLATED_FUNC(has_foo_bar2, foo::bar2<T COMMA_ int>, int(*)(int));
// test them
static_assert(has_foo_bar<int>::value, "something went wrong");
static_assert(!has_foo_bar2<int>::value, "something went wrong");
Других решений пока нет …