Я написал какую-то чепуху с мета-шаблоном, чтобы определить, существуют ли методы класса.
Структура шаблона has_subscript
специализирована таким образом, что вторым параметром шаблона является void
, если первый параметр шаблона имеет оператор нижнего индекса. Если найден оператор нижнего индекса, используется специализация, в противном случае SFINAE по умолчанию использует неспециализированную версию.
У меня есть код, работающий с простой структурой foo (она создана по шаблону, чтобы лучше соответствовать std::vector
), но с std::vector
он неожиданно дает сбой.
демонстрационная ссылка https://godbolt.org/z/5-QzAp
#include <type_traits>
#include <iostream>
#include <vector>
using namespace std;
template <typename>
struct void_wrap
{ using type = void; };
template <typename T, typename = void>
struct has_subscript
{
static constexpr bool value = false;
};
template <typename T>
struct has_subscript <T, typename void_wrap<typename result_of<decltype(&T::operator[])(T,int)>::type>::type >
{
static constexpr bool value = true;
};
template <typename T>
struct foo
{
double operator[](size_t x){return 0.0;}
};
int main()
{
cout << has_subscript<foo<int>>::value;
cout << has_subscript<vector<int>>::value;
}
Вы можете использовать std::is_detected
из основы библиотеки TS v2.
#include <type_traits>
#include <experimental/type_traits>
#include <vector>
template<typename T>
using bracket_op_t = decltype( std::declval<T&>()[0] );
template<typename T>
constexpr bool has_bracket_op = std::experimental::is_detected<bracket_op_t, T>::value;
int main()
{
// static_assert(has_bracket_op<int>, ""); // fails to compile
static_assert(has_bracket_op<std::vector<int>>, "");
}
@roro Я знаю, но, по крайней мере, это решает твою проблему, не так ли? Вы обязаны использовать свой подход?
Я привязан к компилятору С++ 14 и не могу вводить внешние зависимости.
@roro Мой код C++14. Посмотрите на версию компилятора и флаги, которые я использовал. Это GCC 8.3 с std=c++14
. Вы просто должны включить <experimental/type_traits>
.
Это связано с тем, как вы пытаетесь вывести operator[]
, это работает для foo
, но не для std::vector
, потому что оно перегружено.
Выражение typename result_of<decltype(&T::operator[])(T,int)>::type
нельзя использовать, так как &T::operator[]
неоднозначно.
Если вы используете decltype(std::declval<T&>()[int()])
, то он работает как положено (см. здесь).
Это удобный обходной путь, о котором я не знал, но он не отвечает на вопрос.