Предположим, что у нас есть следующий шаблонный класс
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);
Вы можете сделать это, используя 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 );
Я подозреваю, что это не может быть исправлено. (Но я могу ошибаться). Но я подозреваю, что общественное наследство достаточно.
Похоже, я решил проблему.
Я не знаю, пропустил ли я шаг, когда читал о том, как использовать плагин 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 >
и должны быть найдены этим.
Необходимо выполнить довольно активное метапрограммирование шаблона, чтобы определить, является ли один класс X производным от другого Y, в общем случае. В основном X происходит от Y, если:
Андрей Александреску объясняет, как это сделать (наряду со многими другими шаблонными трюками) в своей книге «Modern C++ Design».
Код, который решает проблему, можно найти либо в библиотеке Loki , либо в реализации uSTL , написанной Александреску.
Следующее определяет, является ли что-то оберткой:
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
и должно быть найдено с помощью этого.