Справка с чертами типа

Предположим, что у нас есть следующий шаблонный класс

template<typename T> class Wrap { /* ... */ };

Мы не можем измениться Wrap. Это важно.

Позвольте существуют классы, полученные из Wrap<T>. Например,

class NewInt  : public Wrap<int>     { /* ... */ };
class MyClass : public Wrap<myclass> { /* ... */ };
class Foo     : public Wrap<Bar>     { /* ... */ };

Мы не можем изменить эти классы также. Все классы выше являются третьей стороной. Они не являются моими.

Мне требуется следующее время компиляции type_traits:

template<class T>
struct is_derived_from_Wrap { 
     static const bool value = /* */;
};

В чем я нуждаюсь?

assert(is_derived_from_Wrap<Int>::value == true);  // Indeed I need static assert
assert(is_derived_from_Wrap<MyClass>::value == true);
assert(is_derived_from_Wrap<char>::value == false);
struct X {};
assert(is_derived_from_Wrap<X>::value == false);
5
задан Alexey Malistov 14 January 2010 в 08:51
поделиться

3 ответа

Вы можете сделать это, используя Sfinae, но своего рода волшебного, если вы не знаете, что происходит ...

template<typename T> class Wrap { };

struct myclass {};
struct X {};

class Int     : public Wrap<int>     { /* ... */ };
class MyClass : public Wrap<myclass> { /* ... */ };

template< typename X >
struct is_derived_from_Wrap
{
  struct true_type { char _[1]; };
  struct false_type { char _[2]; };

  template< typename U >
    static true_type test_sfinae( Wrap<U> * w);
  static false_type test_sfinae( ... );

  enum { value = sizeof( test_sfinae( (X*)(0) ) )==sizeof(true_type) };
};


#include <iostream>
#define test(X,Y) std::cout<<( #X " == " #Y )<<"  : "<<( (X)?"true":"false") <<std::endl;

int main()
{
  test(is_derived_from_Wrap <Int>::value, true);
  test(is_derived_from_Wrap <MyClass>::value, true);
  test(is_derived_from_Wrap <char>::value, false);
  test(is_derived_from_Wrap <X>::value, false);
}

Это дает ожидаемый результат

is_derived_from_Wrap <Int>::value == true  : true
is_derived_from_Wrap <MyClass>::value == true  : true
is_derived_from_Wrap <char>::value == false  : false
is_derived_from_Wrap <X>::value == false  : false

, есть пару готов с моим код. Это также вернется правда, если тип - это обертка.

assert(  is_derived_from_Wrap< Wrap<char> >::value == 1 );

Это, вероятно, может быть зафиксировано с использованием немного большей магии Sfinae, если это необходимо.

Это вернет ложь, если вывод не является публичным деривацией (то есть частная или защищена)

struct Evil : private Wrap<T> { };
assert( is_derived_from_Wrap<Evil>::value == 0 );

Я подозреваю, что это не может быть исправлено. (Но я могу ошибаться). Но я подозреваю, что общественное наследство достаточно.

9
ответ дан 14 December 2019 в 01:08
поделиться

Похоже, я решил проблему.

Я не знаю, пропустил ли я шаг, когда читал о том, как использовать плагин nbandroid, но сгенерированный build-impl.xml не включает библиотеки, которые я добавляю с NetBeans при создании APK.

Это компрометирующий фрагмент скрипта муравья:

<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-dex">
    <exec executable="${dx}" failonerror="true">
        <arg value="--dex"/>
        <arg value="--output=${basedir}/${intermediate.dex}"/>
        <arg value="--positions=lines"/>
        <arg path="${build.classes.dir}"/>
    </exec>
</target>

Библиотека включена, и ошибка, упомянутая в моем вопросе, исчезает, если я добавлю последний аргумент:

<arg path="${external.libs.dir}"/>

С помощью external.libs.dir , указывающий на каталог, содержащий банку библиотеки.

Спасибо Кристоферу за то, что я посмотрел на файл build.xml, созданный инструментами командной строки Android (сценарий, созданный при создании проекта Android в NetBeans с плагином nbandroid, совсем другой).


Добавление: Поскольку я говорю о NetBeans, другой способ сделать это - переопределить цель -pre-jar в файле build.xml проекта, вместо вышеуказанного изменения на build-impl.xml. Это делается путем добавления в файл build.xml:

<target name="-pre-jar">
  <copy todir="${build.classes.dir}">
    <fileset dir="${external.libs.dir}" />
  </copy>
</target>

Таким образом, банка библиотеки присутствует вместе со встроенными классами и автоматически включается.

-121--4407676-

Следующее определяет, является ли нечто переносом:

template<class T>
struct is_Wrap { static const bool value = false; };

template<typename T> 
struct is_Wrap< Wrap<T> > { static const bool value = true; };

Поскольку деривация является отношением Is-A, все производные от Wrap < T > также являются переносом < T > и должны быть найдены этим.

-121--4817937-

Необходимо выполнить довольно активное метапрограммирование шаблона, чтобы определить, является ли один класс X производным от другого Y, в общем случае. В основном X происходит от Y, если:

  1. Y может быть неявно преобразован в X
  2. X и Y не один и тот же тип

Андрей Александреску объясняет, как это сделать (наряду со многими другими шаблонными трюками) в своей книге «Modern C++ Design».

Код, который решает проблему, можно найти либо в библиотеке Loki , либо в реализации uSTL , написанной Александреску.

0
ответ дан 14 December 2019 в 01:08
поделиться

Следующее определяет, является ли что-то оберткой:

template<class T>
struct is_Wrap { static const bool value = false; };

template<typename T> 
struct is_Wrap< Wrap<T> > { static const bool value = true; };

Так как производное является отношением Is-A, все, что происходит от Wrap также является Wrap и должно быть найдено с помощью этого.

0
ответ дан 14 December 2019 в 01:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: