Надо написать функцию, которая принимает любой параметр и передаёт его нужной перегрузке другой заранее известной функции.
Пример кода:
#include "stdio.h"
struct CR1
{
CR1 ()
{ printf("CR1 ctor at %x\n", this); }
~CR1 ()
{ printf("CR1 dtor at %x\n", this); }
CR1 (const CR1&)
{ printf("CR1 copyctor at %x\n", this); }
CR1& operator = (const CR1&)
{ printf("CR1 = at %x\n", this); }
};
struct CR2
{
CR2 ()
{ printf("CR2 ctor at %x\n", this); }
~CR2 ()
{ printf("CR2 dtor at %x\n", this); }
CR2 (const CR2&)
{ printf("CR2 copyctor at %x\n", this); }
CR2& operator = (const CR2&)
{ printf("CR2 = at %x\n", this); }
};
struct Base
{
Base (const CR1& cr)
{ printf("const CR1&\n"); }
Base (CR2& cr)
{ printf("CR2&\n"); }
};
struct Derived : Base
{
template <typename Arg>
Derived(const Arg& arg) : Base(arg) {} // что сюда писать?
};
int main ()
{
{
CR1 cr;
Derived der(cr);
}
getchar();
return 0;
}
Допустим, Base переделывать нельзя. Надо, чтобы Derived жрал все конструкторы базы.
Конструктор Derived — типа универсальный передатчик. Но что-то не заладилось.
Сейчас у меня стоит const Arg& arg, и если я попробую передать в конструктор CR2 вместо CR1, то компилятор меня пошлёт, потому что константную ссылку переделать в неконстантную нельзя.
Если я напишу "универсальный конструктор" как Arg& arg, то будет проблема с попыткой передать в него временный объект.
warning C4239: nonstandard extension used : 'argument' : conversion from 'CR1' to 'CR1 &'
Если я напишу его как Arg arg, то проблем никаких не будет. Будет лишь лишнее копирование, что видно по выводу программы.
Написать два конструктора не предлагать, потому что у меня может быть 8 таких параметров.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
TB>>Написать два конструктора не предлагать, потому что у меня может быть 8 таких параметров.
V>Именно для этого и были придуманы rvalue references. Google в помощь.
А средствами ++03?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
TB>>>Написать два конструктора не предлагать, потому что у меня может быть 8 таких параметров.
V>>Именно для этого и были придуманы rvalue references. Google в помощь.
TB>А средствами ++03?
Никак. Именно потому и придумали rvalue references, что без них никак.
Здравствуйте, Vamp, Вы писали:
V>Никак. Именно потому и придумали rvalue references, что без них никак.
Ну типа шаблон ProxyArg<T>::type определить, в нём определять, константен ли объект, и для константы делать const&, для неконстанты просто &.
Я просто на вывернутых шаблонах с хитрыми специализациями, сфинаями итд импровизировать не умею.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Я просто на вывернутых шаблонах с хитрыми специализациями, сфинаями итд импровизировать не умею.
и не надо, оно нужно в << 1% случаев. если работодатель требует это как необходимость, предлагаю отфутболить его и выбрать другого более вменяемого.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, T4r4sB, Вы писали:
TB>>Я просто на вывернутых шаблонах с хитрыми специализациями, сфинаями итд импровизировать не умею. V>и не надо, оно нужно в << 1% случаев. если работодатель требует это как необходимость, предлагаю отфутболить его и выбрать другого более вменяемого.
Да и этот 1% не понадобился бы, если бы дохлый страус вовремя придумал рефлексию времени компиляции. Так сложно что ли добавить в язык constexpr-функцию "есть ли у такого класса такой метод с такой сигнатурой"?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Да и этот 1% не понадобился бы, если бы дохлый страус вовремя придумал рефлексию времени компиляции. Так сложно что ли добавить в язык constexpr-функцию "есть ли у такого класса такой метод с такой сигнатурой"?
Ты постоянно пытаешься исправить проблемы своей кривой архитектуры за счёт введения непонятных вещей в язык, которые там кроме тебя никому не нужны. Не надо так
Здравствуйте, T4r4sB, Вы писали:
TB>Надо написать функцию, которая принимает любой параметр и передаёт его нужной перегрузке другой заранее известной функции.
TB>Сейчас у меня стоит const Arg& arg, и если я попробую передать в конструктор CR2 вместо CR1, то компилятор меня пошлёт, потому что константную ссылку переделать в неконстантную нельзя.
Здравствуйте, CEMb, Вы писали:
CEM>Ты постоянно пытаешься исправить проблемы своей кривой архитектуры за счёт введения непонятных вещей в язык, которые там кроме тебя никому не нужны. Не надо так
В 99% тем в профильном разделе можно зайти и не читая написать "скорее всего, у тебя неправильная архитектура, раз тебе это нужно". Поэтому я такие посты считаю дурным тоном.
Ну и рефлексию времени компиляции назвать "никому не нужной" — это уже запредельная дерзость.
Подожди, а может ты действительно написал пост, не читая?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Я имею в виду — нет нормального решения вопроса. К твоему коду нетрудно подобрать пример, который приведёт к неожиданностям.
Зависит от того, шашечки или ехать.
Если у тебя есть конкретная проблема с восемью сигнатурами конструкторов, для которой хочется придумать быстрое решение, — то, может быть, именно на твоём коде не будет неожиданностей.
А если ты хочешь найти решение "вообще", с придумыванием контрпримеров, — это другой разговор. (Вполне практический, если ты пишешь библиотеку для широкого использования). Но тут встаёт вопрос архитектуры
И кстати, если уж зашёл разговор о практических решениях, то пожалуйста, расскажи реальную задачу и покажи эскиз реального кода. А не переабстрагированного — CR1, CR2, Base, Derived — возможно, здесь ты с водой выплеснул ребёнка. Опять же, зачем морозить сигнатуры и зачем наследовать?
Здравствуйте, T4r4sB, Вы писали:
CEM>>Ты постоянно пытаешься исправить проблемы своей кривой архитектуры за счёт введения непонятных вещей в язык, которые там кроме тебя никому не нужны. Не надо так
TB>В 99% тем в профильном разделе можно зайти и не читая написать "скорее всего, у тебя неправильная архитектура, раз тебе это нужно". Поэтому я такие посты считаю дурным тоном.
Нет, нельзя. Твоя доработка сильно утяжелит внутреннюю структуру классов, кому это нужно, при условии, что не будет использоваться? Не, ты можешь пообщаться с авторами, предложить идею. Вот к примеру, архитектурное решение с виртуальными таблицами методов в классе существует, их можно включить и выключить. Если получится ровно так же, я не против.
TB>Ну и рефлексию времени компиляции назвать "никому не нужной" — это уже запредельная дерзость.
TB>Подожди, а может ты действительно написал пост, не читая?
Читал, и всё остальное, в том числе "почему в с++ нет проверки границ массива" тоже, потому и пишу.
Извини, конечно, но почему бы тебе не попробовать на Java писать? У Java более подходящая биосфера, там гибко можно использовать огромное количество библиотек, которые решают все проблемы.
Здравствуйте, Кодт, Вы писали:
К>И кстати, если уж зашёл разговор о практических решениях, то пожалуйста, расскажи реальную задачу и покажи эскиз реального кода. А не переабстрагированного — CR1, CR2, Base, Derived — возможно, здесь ты с водой выплеснул ребёнка. Опять же, зачем морозить сигнатуры и зачем наследовать?
Очевидно, что тут имеется в виду тот же вопрос, который возникает при написании emplace_back или make_shared (только в ++03). Зачем притворяться, будто ты не понял, о чём речь?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CEMb, Вы писали:
CEM>Нет, нельзя. Твоя доработка сильно утяжелит внутреннюю структуру классов, кому это нужно, при условии, что не будет использоваться? Не, ты можешь пообщаться с авторами, предложить идею. Вот к примеру, архитектурное решение с виртуальными таблицами методов в классе существует, их можно включить и выключить. Если получится ровно так же, я не против.
Чего-чего, внутренняя структура, виртуальные таблицы?
Я же написал: рефлексия времени компиляции.
Не, ты точно читаешь очень невнимательно, торопясь вставить очередную коронную фразу.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
CEM>>Нет, нельзя. Твоя доработка сильно утяжелит внутреннюю структуру классов, кому это нужно, при условии, что не будет использоваться? Не, ты можешь пообщаться с авторами, предложить идею. Вот к примеру, архитектурное решение с виртуальными таблицами методов в классе существует, их можно включить и выключить. Если получится ровно так же, я не против.
TB>Чего-чего, внутренняя структура, виртуальные таблицы? TB>Я же написал: рефлексия времени компиляции. TB>Не, ты точно читаешь очень невнимательно, торопясь вставить очередную коронную фразу.
А, да, каюсь, я не прав про классы, это про время компиляции.
Проблема определения на момент компиляции наличия у класса метода с нужной сигнатурой решается, например, шаблонами.
class CGood
{
protected:
void foo(const int& i){};
};
class CBad
{
protected:
void foo(int& i){};
};
template<class T> class CT: public T
{
public:
CT(const int& i);
};
template<class T> CT<T>::CT(const int& i)
{
foo(i);
}
// once in code:
CT<CGood> cg(1); // OK
CT<CBad> cb(1); // Error
Здравствуйте, CEMb, Вы писали:
CEM>Проблема определения на момент компиляции наличия у класса метода с нужной сигнатурой решается, например, шаблонами.
...
CEM> CT<CGood> cg(1); // OK CEM> CT<CBad> cb(1); // Error CEM>[/ccode]
А теперь осталось это ОК/Еггог запихать в сфинью, чтобы получить HasMethod::value, и вся эта хренота вместо одной строки, которую уже десять лет просят добавить в язык.
Здравствуйте, T4r4sB, Вы писали:
CEM>>Проблема определения на момент компиляции наличия у класса метода с нужной сигнатурой решается, например, шаблонами. TB>...
CEM>> CT<CGood> cg(1); // OK CEM>> CT<CBad> cb(1); // Error CEM>>[/ccode]
TB>А теперь осталось это ОК/Еггог запихать в сфинью, чтобы получить HasMethod::value, и вся эта хренота вместо одной строки, которую уже десять лет просят добавить в язык.
Интересная задачка
Напиши хотя бы псевдокодом, как ты себе это видишь?
Я пока вижу только условное ветвление в конструкторе, но компилятор всё равно ругнётся же на отсутствие метода, в обоих классах причём (в одном одного, в другом другого, как мне видится), поэтому хотелось бы увидеть псевдокод
Здравствуйте, T4r4sB, Вы писали:
TB>Очевидно, что тут имеется в виду тот же вопрос, который возникает при написании emplace_back или make_shared (только в ++03). Зачем притворяться, будто ты не понял, о чём речь?
Не разглядел emplace_back и make_shared в исходном сообщении. Старею?
Здравствуйте, T4r4sB, Вы писали:
TB>Да фиг знает, чёто такое, но это не сработает
Конечно, такое не сработает, потому что тут получается вывод типов сразу с двух сторон:
— из фактического типа аргумента
— из требований к аргументу, взятых из базы
А это запрещено стандартом.
Если отвлечься от конструктора, то решение именно так и выглядит
bar(X&);
bar(const Y&);
bar(volatile Z&);
template<class T> auto foo( T with cv-qualifiers etc & t ) -> sfinae if fits to bar(t) then void
{ bar(t); }
template<class T> auto foo( T with another cv-qualifiers etc & t ) -> sfinae if fits to bar(t) then void
{ bar(t); }
Конечно, если foo имеет много аргументов, это будет комбинаторный взрыв.
Но можно прибегнуть к частичному применению — т.е. заменить foo(T&&,U&&,V&&) на foo.start(T&&).and(U&&).and(V&&).go().
Каждая промежуточная функция унарная, сможет разобраться с двумя (или четыремя, если ещё volatile) вариантами и заначить правильную ссылку с правильным типом.
А превратить кортеж в серию вызовов — это boost preprocessor. Там даже основной тип для вариадиков — это именно sequence, (t)(u)(v).
Будет FOO(t,u,v,etc...) превращаться в foo(t)(u)(v)(etc...).go()
Ну или выбросить старый компилятор... Но это, как я понимаю, не вариант.