Вывести пакет параметров без явной передачи его в качестве параметра шаблона?

#c #templates #parameters #c 11 #variadic-templates

#c #шаблоны #параметры #c 11 #переменные-шаблоны

Вопрос:

Простите любое незнание вывода типа C в этом, но я хотел бы иметь возможность переносить определение пакета параметров, чтобы позже я мог протестировать внутренний тип. Возможно ли это? Что-то вроде:

 template <typename... Args> struct Entity {

    struct Inner {
        typedef Args... entity_args_t;
    };

    struct SomeOtherInner {
        typedef Args... entity_args_t;
    };
};

struct ThingA : Entity<int, string> {
};

struct ThingB : Entity<string, string> {
};

//Want to accept variations of Entity<...>::Inner,
//not Entity<...>::SomeOtherInner
template<typename I>
struct is_Entity_Inner {
    static const bool value
        = is_same<
            typename Entity<typename I::entity_args_t...>::Inner
            , I
        >::value
    ;
};
  

Oui? Нет?

Ответ №1:

Определить:

 template<typename ...> struct types;
  

Затем:

 template <typename... Args> struct Entity {

    struct Inner {
        typedef types<Args...> entity_args_t;
    };

    struct SomeOtherInner {
        typedef types<Args...> entity_args_t;
    };
};
  

Затем вы можете перейти entity_args_t к шаблону, который имеет частичную специализацию для types<T...> . Если вы введете def Entity , вы можете вместо этого написать частичную специализацию для Entity<T...> , что может иметь больше смысла в вашем случае

 template <typename... Args> struct Entity {

    struct Inner {
        // Equivalent: typedef Entity entity_args_t;
        typedef Entity<Args...> entity_args_t;
    };

    struct SomeOtherInner {
        typedef Entity<Args...> entity_args_t;
    };
};
  

Итак, имея typedef для entity_args_t equal Entity<Args...> , вы могли бы написать это следующим образом (непроверенный, но должен работать):

 template<typename ProbablyInner, typename ProbablyEntity>
struct is_inner_impl : std::false_type 
{ };

template<typename ProbablyInner, typename ...Args>
struct is_inner_impl<ProbablyInner, Entity<Args...>> 
  : std::is_same<
      typename Entity<Args...>::Inner
      ProbablyInner>
{ };

template<typename ProbablyInner, typename = std::true_type>
struct is_inner : std::false_type 
{ };

template<typename ProbablyInner>
struct is_inner<ProbablyInner, 
  std::integral_constant<bool, is_inner_impl<
    ProbablyInner, 
    typename ProbablyInner::entity_args_t>::value>>
  : std::true_type 
{ };
  

Комментарии:

1. Итак, в is_Entity_Inner метафункции я бы вместо этого имел is_same<typename I::entity_args_t::template Inner, I>::value ?

2. @pheedbaq критическая точка — это то, к чему вы обращаетесь ::entity_args_t . Если вы хотите получить is_inner yield false для произвольных других типов, вам нужно получить доступ к типу в контексте SFINAE, чтобы, если не вызывается элемент ::entity_args_t , не возникло ошибки во время компиляции.

3. @litb Не совсем уверен, что понял ваш последний комментарий. Это то, что typename = void выполняется в качестве второго параметра is_inner ? Если ::entity_args_t элемент существует, то компилятор сопоставляет его со специализацией. Если нет, то, даже если элемент не существует, он сопоставляет его с typename = void версией?

4. @pheedbaq впоследствии я изменил свой код, чтобы не использовать enable_if . Я думаю, что это раздувает код. Если ::entity_args_t существует, то он может учитывать специализацию и соответствует ли она аргументам (аргументы являются <whatever is passed, void> ). enable_if то, что используется, всегда даст результат void в случае успеха (если элемент существует). В случае неуспеха (то есть когда is_inner_impl<>::value вычисляется false ) не существует ::type элемента, и поэтому возникает ошибка SFINAE. Примерно то же самое происходит с моей integral_constant<> версией сейчас.

5. ОК. Кажется, я понял. Очень признателен!