traductor traducir traduccion titulo shopkins google etiqueta español c++ c++11 templates types type-conversion

c++ - traducir - ¿Cómo exigir una firma de función exacta en el idioma de detección?



status traductor google (2)

Supongamos que tengo un tipo T y quiero detectar si tiene un operador de subíndices al que puedo llamar con otro tipo de Index . El siguiente ejemplo funciona bien:

#include <type_traits> #include <vector> template < typename T, typename Index > using subscript_t = decltype(std::declval<T>()[std::declval<Index>()]); int main() { using a = subscript_t< std::vector<int>, size_t >; using b = subscript_t< std::vector<int>, int >; }

Sin embargo, quiero que la función se detecte si y solo si la firma de la función coincide exactamente. En el ejemplo anterior, me gustaría la declaración subscript_t< std::vector<int>, int >; lanzar un error como no viable overloaded operator[] , porque la firma del operador de subíndice para std::vector es

std::vector<T, std::allocator<T>>::operator[](size_type pos);

donde size_type en GCC unsigned long tiene unsigned long . ¿Cómo puedo evitar que tenga lugar la conversión implícita de int a size_t ?


Puedes hacerlo:

template <typename Index, typename ClassType, typename ReturnType> constexpr bool arg_t(ReturnType (ClassType::*)(Index)) { return true; } template <typename T, typename Index> struct subscript_t { static_assert(arg_t<Index>(&T::operator[])); };

Tenga en cuenta que necesitará crear una instancia de subscript_t , no simplemente nombrar su tipo:

int main() { subscript_t< std::vector<int>, size_t > a; subscript_t< std::vector<int>, int > b; }

Otra forma, que le permite determinar el mensaje de error exacto:

template <typename ClassType, typename ReturnType, typename ArgType> constexpr ArgType arg_t(ReturnType (ClassType::*)(ArgType)) { return {}; } template <typename T, typename Index> struct subscript_t { using Actual = decltype(arg_t(&T::operator[])); static_assert(std::is_same<Index, Actual>::value, "oops"); };


Con is_detected , puede hacer

template <typename T, typename Ret, typename Index> using subscript_t = std::integral_constant<Ret (T::*) (Index), & T::operator[]>; template <typename T, typename Ret, typename Index> using has_subscript = is_detected<subscript_t, T, Ret, Index>; static_assert(has_subscript<std::vector<int>, int&, std::size_t>::value, "!"); static_assert(!has_subscript<std::vector<int>, int&, int>::value, "!");

Manifestación

Escribí esto en SO Documentation:

is_detected

Para generalizar la creación type_trait: basado en SFINAE, hay rasgos experimentales detected_or o detected_t , is_detected .

Con los parámetros de la plantilla typename Default , template <typename...> Op y typename ... Args :

  • is_detected : alias de std::true_type o std::false_type dependiendo de la validez de Op<Args...>
  • detected_t : alias de Op<Args...> o nonesuch dependiendo de la validez de Op<Args...> .
  • detected_or : alias de una estructura con value_t que es is_detected , y type Op<Args...> o Default dependiendo de la validez de Op<Args...>

que se puede implementar usando std::void_t para SFINAE de la siguiente manera:

namespace detail { template <class Default, class AlwaysVoid, template<class...> class Op, class... Args> struct detector { using value_t = std::false_type; using type = Default; }; template <class Default, template<class...> class Op, class... Args> struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> { using value_t = std::true_type; using type = Op<Args...>; }; } // namespace detail // special type to indicate detection failure struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(nonesuch const&) = delete; void operator=(nonesuch const&) = delete; }; template <template<class...> class Op, class... Args> using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t; template <template<class...> class Op, class... Args> using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type; template <class Default, template<class...> class Op, class... Args> using detected_or = detail::detector<Default, void, Op, Args...>;

Los rasgos para detectar la presencia del método se pueden implementar simplemente:

typename <typename T, typename ...Ts> using foo_type = decltype(std::declval<T>().foo(std::declval<Ts>()...)); struct C1 {}; struct C2 { int foo(char) const; }; template <typename T> using has_foo_char = is_detected<foo_type, T, char>; static_assert(!has_foo_char<C1>::value, "Unexpected"); static_assert(has_foo_char<C2>::value, "Unexpected"); static_assert(std::is_same<int, detected_t<foo_type, C2, char>>::value, "Unexpected"); static_assert(std::is_same<void, // Default detected_or<void, foo_type, C1, char>>::value, "Unexpected"); static_assert(std::is_same<int, detected_or<void, foo_type, C2, char>>::value, "Unexpected");