Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
#1

Выбор кода при компиляции - C++

24.06.2014, 13:47. Просмотров 538. Ответов 19
Метки нет (Все метки)

Здравствуйте!
Столкнулся с почти аналогичной проблемой, как и описанная в данной статье:
http://www.solarix.ru/for_developers...e-switch.shtml
В ней идет разговор о выборе кода при компиляции в зависимости от типа входных данных. Моя же проблема, по сравнению со статьей, усложняется (а может и упрощается) тем, что нужно в зависмости от типа данных передавать в функцию еще и разное число параметров, а не одинаковое их число одинаковых типов как в статье.
То есть нужно написать функцию (функции), чтобы алгоритм был примерно такой:
C++
1
2
3
4
5
6
7
template < typename T > void SomeFunction(T t, int x)
{
if (/*тип T удовлетворяет условию*/)
OtherFunction(t);
else
OtherFunction(t, x);
}
Буду признателен, если мне помогут.
P.S. Только заранее прошу не предлагать мне использовать альтернативные пути решения задачи, а предлагать только решения методами шаблонного программирования )))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.06.2014, 13:47
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Выбор кода при компиляции (C++):

Выбор кода для компиляции на основании сравнения параметров шаблона - C++
Здравствуйте. Помогите, пожалуйста, разобраться со следующим вопросом. Необходимо выбирать компилируемый код в зависимости от какого-либо...

Ошибка при компиляции кода - C++
не могу понять в чем ошибка при компиляции этого кода: #include &lt;unistd.h&gt; #include &lt;stdlib.h&gt; #include &lt;assert.h&gt; #include...

Предупреждения при компиляции кода - C++
Вообщем есть код с простенькой реализацией классического Singleton + его удаление через класс SingletonDestroyer... class Singleton; ...

Ошибка при компиляции кода - C++
#include &lt;iostream&gt; using namespace std; int find_substr(char *sub, char *str); int main() { int index; index =...

Ошибка при компиляции кода - C++
Добрый вечер, Создайте void функцию c именем round().которая округляет значение своего аргумента типа double до ближайшего целого значения....

Ошибка при компиляции простого кода с указателем - C++
В чем ошибка? #include &lt;iostream&gt; using namespace std; int main() { int *y; *y=10; }

19
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
24.06.2014, 13:54 #2
Если в зависимости от типа нужно выполнять определенный код, то просто специализируй шаблон функции. Безо всяких if внутри.
0
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 13:56  [ТС] #3
Я бы так и сделал, если бы, типов было только 2, но их несколько побольше и для каждого специализацию писать лениво)))
Но в конце концов я так и сделаю, если иного решения не найдется))
0
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
24.06.2014, 13:59 #4
Цитата Сообщение от Variag Посмотреть сообщение
и для каждого специализацию писать лениво)))
А в чем разница-то? Ты тут так же будешь для каждого типа будешь писать свой if.
0
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 14:04  [ТС] #5
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point. Признак писать короче чем специализацию для каждого типа)
0
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
24.06.2014, 14:18 #6
Цитата Сообщение от Variag Посмотреть сообщение
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point
Это уже уточнение. Тогда да, короче.
0
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 11:28  [ТС] #7
Ну а все-таки) Неужели никто не знаком в достаточной мере с программированием шаблонов?))
0
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
25.06.2014, 11:30 #8
Variag, ты вопрос задай по-нормальному. Не понятно, что тебе нужно. Написал ты свой пример того, как собираешься делать. И в чем вопрос-то? Чем тебя твой "алгоритм" конкретно не устраивает?
0
ForEveR
В астрале
Эксперт С++
7979 / 4738 / 321
Регистрация: 24.06.2010
Сообщений: 10,543
Завершенные тесты: 3
25.06.2014, 15:34 #9
Выглядить оно будет как-то так (но можно и через специализации конечно). А дальше нужны уточнения от вас.

C++
1
2
3
4
5
6
7
template < typename T > void SomeFunction(T t, int x)
{
if (!std::is_integral<T>::value)
   OtherFunction(t);
else
   OtherFunction(t, x);
}
0
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 17:02  [ТС] #10
Да, наверное, я не совсем точно и не совсем полно указал исходные данные...
Уточню: предложенный Вами метод не будет работать. Связано это с тем, что компилятору же надо оттранслировать обе ветки if-else, а типы T, для которых вся эта бодяга и мутится, фактически делятся на два типа. Допустим, для простоты, что делается это по указанному Вами признаку std::is_integral<T>, хотя это, конечно, не так. Но проблема в том, что для одних типов функция OtherFunction() принимает один аргумент, а для других - два. Текст этих функций будет примерно такой:
C++
1
2
3
4
5
6
7
8
9
template < typename T > void OtherFunction(T t)
{
t.SomeMethod();
}
 
template < typename T > void OtherFunction(T t, int x)
{
t.SomeMethod(x);
}
В принципе, эти две функции OtherFunction(), можно, наверное, вообще опустить, как лишнее промежуточное звено...
Соответственно, здесь будет ошибка компиляции по причинам не соответствия количества аргументов для методов, потому как для одних типов SomeMethod() принимает int в качестве значения, а для других нет. Может так понятнее будет?
Вы меня извините, это мой первый опыт шаблонного программирования, и я пока плоховато мыслю в категориях шаблонов))
0
0x10
2475 / 1648 / 247
Регистрация: 24.11.2012
Сообщений: 4,069
25.06.2014, 18:33 #11
Читаю и все равно ничего не могу понять. Примеры неправдоподобные и надуманные. Могу от фонаря привести такой кусок кода, но более чем уверен, что у Вас случай гораздо проще и, вероятно, есть ошибки в подходе к решению задачи.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
 
template <class T>
typename std::enable_if<!std::is_integral<T>::value, void>::type
Function(T obj)
{
    std::cout << "Some non-integral: " << obj << std::endl;
}
 
template <class T>
typename std::enable_if<std::is_integral<T>::value, void>::type
Function(T obj)
{
    std::cout << "Some integral: " << obj << std::endl;
}
 
int main()
{
    Function(0x10);
    Function(0.10);
}
0
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 22:13  [ТС] #12
Могу от фонаря привести такой кусок кода
Вот именно что от фонаря. Такой пример и я видел на просторах интеренета, но он мне не подходит. Вообще не в тему))

Добавлено через 40 минут
Уж коли пошла такая пьянка, сформулирую еще раз проблему:
Есть у меня классы: ClassA, ClassB, ClassC, ClassD, ... ClassZ. В каждом из этих классов есть метод. Только в одних классах он параметров не принимает и выглядит как void SomeMethod(), а в других принимает int и выглядит как void SomeMethod(int x).
Задача:
Написать глобальную шаблонную функцию template < typename T > void SomeFunction(T t, int x), которая будет в зависимости от типа T вызывать соответствующий этому типу метод SomeMethod(), либо с параметром, либо без.
Надеюсь, стало понятнее)) Еще раз извиняюсь, если раньше было менее понятно.
И прошу, все-таки не обсуждать мой подход к решению задачи. Я пробовал и все классы унаследовать от базового, и наследовать от двух базовых, и много чего еще, но все это мне не подходит по разным причинам. Так что давайте все-таки сосредоточимся на предлагаемой мной задаче, а не будем переписывать условие)))
0
gray_fox
What a waste!
1521 / 1226 / 70
Регистрация: 21.04.2012
Сообщений: 2,565
Завершенные тесты: 3
26.06.2014, 00:25 #13
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Variag,
Так?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <utility>
#include <type_traits>
 
 
namespace detail {
 
template<typename T>
class has_noarg_foo_method {
    
    using yes = char(&)[1];
    using no  = char(&)[2];
    
    template<typename>
    struct helper;
    
    template<typename>
    static no  check(...);
    
    template<typename U>
    static yes check(helper<decltype(std::declval<U>().foo())> *);
 
public:
   static constexpr bool value = sizeof (check<T>(nullptr)) == sizeof (yes);
};
 
}
 
template<typename T>
struct has_noarg_foo_method : std::integral_constant<bool, detail::has_noarg_foo_method<T>::value> {};
 
 
struct one {
    
   void foo() const {
      std::cout << "foo()" << std::endl;
   }
};
 
struct two {
    
   void foo(int x) const {
      std::cout << "foo(" << x << ")" << std::endl;
   }
};
 
namespace detail {
    
enum class enabler;
 
}
 
template<typename T>
using enable_if = typename std::enable_if<T::value, detail::enabler>::type;
 
template<typename T>
using disable_if = typename std::enable_if<!T::value, detail::enabler>::type;
 
template<typename T, enable_if<has_noarg_foo_method<T>>...>
void do_foo(T const& obj, int) {
   obj.foo();
}
 
template<typename T, disable_if<has_noarg_foo_method<T>>...>
void do_foo(T const& obj, int const x) {
   obj.foo(x);
}
 
 
int main() {
   do_foo(one{}, 1);
   do_foo(two{}, 2);
}
http://ideone.com/VqHAFR
3
DrOffset
7351 / 4451 / 1009
Регистрация: 30.01.2014
Сообщений: 7,292
26.06.2014, 04:13 #14
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от Variag Посмотреть сообщение
Вот именно что от фонаря. Такой пример и я видел на просторах интеренета, но он мне не подходит. Вообще не в тему))
Еще как в тему.
Такие вещи через enable_if как раз и делаются. Только предикат нужно другой.
Код для С++03 (enable_if в этом случае можно взять из boost, либо написать самому, как я) - реализация через SFINAE:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <cstdio>
 
struct ClassA
{
    void SomeMethod()      { puts(__PRETTY_FUNCTION__); }
};
 
struct ClassB
{
    void SomeMethod(int a) { puts(__PRETTY_FUNCTION__); }
};
 
struct ClassC
{
    void SomeMethod()      { puts(__PRETTY_FUNCTION__); }
};
 
template <typename T>
struct has_param
{
    struct param    {};
    struct no_param { char a[2]; };
 
    static param    test(void (T::*)(int));
    static no_param test(void (T::*)());
 
    enum
    {
        value = sizeof(test(&T::SomeMethod)) == 1
    };
};
 
template <bool, class T = void>
struct enable_if
{};
 
template <class T>
struct enable_if<true, T>
{
  typedef T type;
};
 
template <typename T>
typename enable_if<has_param<T>::value, void>::type
    SomeFunction(T t, int x)
{
    t.SomeMethod(x);
}
 
template <typename T>
typename enable_if<!has_param<T>::value, void>::type
    SomeFunction(T t, int x)
{
    t.SomeMethod();
}
 
int main()
{
    ClassA a;
    ClassB b;
    ClassC c;
 
    SomeFunction(a, 1);
    SomeFunction(b, 1);
    SomeFunction(c, 1);
}
Код для С++11 будет немного отличаться, но в целом принцип тот же. Могу привести, если надо, но щас лень.

А вообще я бы сделал так (без шаблонных изысков, старая добрая перегрузка):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
 
struct ClassA
{
    void SomeMethod()      { puts(__PRETTY_FUNCTION__); }
};
 
struct ClassB
{
    void SomeMethod(int a) { puts(__PRETTY_FUNCTION__); }
};
 
struct ClassC
{
    void SomeMethod()      { puts(__PRETTY_FUNCTION__); }
};
 
template <typename T>
inline void some_function_proxy(T & t, void (T::*ptr)(), int)
{
    (t.*ptr)();
}
template <typename T>
inline void some_function_proxy(T & t, void (T::*ptr)(int), int x)
{
    (t.*ptr)(x);
}
 
template <typename T>
void SomeFunction(T t, int x)
{
    some_function_proxy(t, &T::SomeMethod, x);
}
 
int main()
{
    ClassA a;
    ClassB b;
    ClassC c;
 
    SomeFunction(a, 1);
    SomeFunction(b, 1);
    SomeFunction(c, 1);
}
Добавлено через 3 часа 36 минут
Кстати в С++11, есть довольно красивый и простой способ обобщить проверку сигнатуры функции. Ее можно использовать при решении задачи ТС:
иллюстрация
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <type_traits>
#include <iostream>
 
struct ClassA
{
    void SomeMethod()      {}
};
 
struct ClassB
{
    void SomeMethod(int a) { }
};
 
struct ClassC
{
    void SomeMethod()      { }
};
 
void SomeFunc(int a) { }
 
//-----
 
template <typename T>
struct remove_class_from_member;
 
template <typename Ret, typename Class, typename ...Args>
struct remove_class_from_member<Ret (Class::*)(Args...)>
{
    typedef Ret (*type)(Args...);
};
 
template <typename Ret, typename ...Args>
struct remove_class_from_member<Ret (*)(Args...)>
{
    typedef Ret (*type)(Args...);
};
 
template <typename T, typename U>
struct check_sig
    : std::is_same<typename remove_class_from_member<T>::type, typename std::decay<U>::type>
{};
 
int main()
{
    std::cout << check_sig<decltype(&ClassA::SomeMethod), void()>::value << '\n';
    std::cout << check_sig<decltype(&ClassB::SomeMethod), void(int)>::value << '\n';
    std::cout << check_sig<decltype(&ClassC::SomeMethod), void()>::value << '\n';
    std::cout << check_sig<decltype(&SomeFunc), void(int)>::value << '\n';
}
6
Variag
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
26.06.2014, 08:58  [ТС] #15
Еще как в тему.
Такие вещи через enable_if как раз и делаются. Только предикат нужно другой.
Спасибо, знаю что через enable_if, просто то решение не соответствовало поставленной задачи.
Спасибо gray_fox и DrOffset за Ваши решения. Теперь хотелось бы пару комментариев для поднятия образованности.
Как я понимаю, здесь ведь enable_if используется для "включения/выключения" возвращаемого значения функции, и таким образом, "включает/выключает" всю функцию?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename T>
typename enable_if<has_param<T>::value, void>::type
    SomeFunction(T t, int x)
{
    t.SomeMethod(x);
}
 
template <typename T>
typename enable_if<!has_param<T>::value, void>::type
    SomeFunction(T t, int x)
{
    t.SomeMethod();
}
За метод проверки сигнатуры функции отдельное спасибо)
0
26.06.2014, 08:58
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.06.2014, 08:58
Привет! Вот еще темы с ответами:

Ошибки C2678 и C2679 при компиляции кода - C++
#include &lt;iostream&gt; #include &lt;string&gt; #include &quot;stdafx.h&quot; #include &quot;iostream&quot; #include &quot;conio.h&quot; using namespace std; ...

При компиляции любого кода получаю ошибку - C++
При компиляции любого кода получаю ошибку C:\Users\Mefelis\Documents\Makefile.win Error 1

Ошибка при компиляции, нужно чтобы программа сделала выбор - C++
Здравствуйте. Пытаюсь решить формулу (вычислить высоту треугольника) с помощью С++, не могу сделать так чтобы программа сделала выбор когда...

При компиляции кода вылазит ошибка "error C2027: use of undefined type 'SldWorks'" - C++
При компиляции кода вылазит ошибка &quot;error C2027: use of undefined type 'SldWorks'&quot;. Я писал на чистых плюсах! #include &quot;stdafx.h&quot; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru