Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/9: Рейтинг темы: голосов - 9, средняя оценка - 4.56
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1

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

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

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Столкнулся с почти аналогичной проблемой, как и описанная в данной статье:
http://www.solarix.ru/for_deve... itch.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
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.06.2014, 13:47
Ответы с готовыми решениями:

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

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

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

19
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 13:54
Если в зависимости от типа нужно выполнять определенный код, то просто специализируй шаблон функции. Безо всяких if внутри.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 13:56  [ТС]
Я бы так и сделал, если бы, типов было только 2, но их несколько побольше и для каждого специализацию писать лениво)))
Но в конце концов я так и сделаю, если иного решения не найдется))
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 13:59
Цитата Сообщение от Variag Посмотреть сообщение
и для каждого специализацию писать лениво)))
А в чем разница-то? Ты тут так же будешь для каждого типа будешь писать свой if.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 14:04  [ТС]
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point. Признак писать короче чем специализацию для каждого типа)
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 14:18
Цитата Сообщение от Variag Посмотреть сообщение
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point
Это уже уточнение. Тогда да, короче.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 11:28  [ТС]
Ну а все-таки) Неужели никто не знаком в достаточной мере с программированием шаблонов?))
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
25.06.2014, 11:30
Variag, ты вопрос задай по-нормальному. Не понятно, что тебе нужно. Написал ты свой пример того, как собираешься делать. И в чем вопрос-то? Чем тебя твой "алгоритм" конкретно не устраивает?
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
25.06.2014, 15:34
Выглядить оно будет как-то так (но можно и через специализации конечно). А дальше нужны уточнения от вас.

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
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 17:02  [ТС]
Да, наверное, я не совсем точно и не совсем полно указал исходные данные...
Уточню: предложенный Вами метод не будет работать. Связано это с тем, что компилятору же надо оттранслировать обе ветки 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
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
25.06.2014, 18:33
Читаю и все равно ничего не могу понять. Примеры неправдоподобные и надуманные. Могу от фонаря привести такой кусок кода, но более чем уверен, что у Вас случай гораздо проще и, вероятно, есть ошибки в подходе к решению задачи.
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
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 22:13  [ТС]
Могу от фонаря привести такой кусок кода
Вот именно что от фонаря. Такой пример и я видел на просторах интеренета, но он мне не подходит. Вообще не в тему))

Добавлено через 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
What a waste!
 Аватар для gray_fox
1610 / 1302 / 180
Регистрация: 21.04.2012
Сообщений: 2,733
26.06.2014, 00:25
Лучший ответ Сообщение было отмечено Variag как решение

Решение

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
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.06.2014, 04:13
Лучший ответ Сообщение было отмечено Variag как решение

Решение

Цитата Сообщение от 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
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
26.06.2014, 08:58  [ТС]
Еще как в тему.
Такие вещи через 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
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
26.06.2014, 10:28
Цитата Сообщение от Variag Посмотреть сообщение
Как я понимаю, здесь ведь enable_if используется для "включения/выключения" возвращаемого значения функции, и таким образом, "включает/выключает" всю функцию?
Смотрим на возможный вариант реализации: http://en.cppreference.com/w/cpp/types/enable_if
В специализации для false отсутствует вложенный тип type, следовательно все определение
C++
1
2
3
template <typename T>
typename enable_if<false, void>::type
SomeFunction(T t, int x)
становится невалидным, но это приводит не к ошибке компиляции, а к исключению функции из списка кандидатов (см идиому SFINAE).
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.06.2014, 11:01
В С++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
template<typename T, typename E>
constexpr auto has_function_with_no_arg(T&& obj, const E& e = E()) -> decltype((obj.*e)(), void());
 
template<typename T, typename E>
constexpr auto has_function_with_one_arg(T&& obj, const E& e = E()) -> decltype((obj.*e)(int()), void());
 
template<typename T>
auto SomeFunction(T&& obj, int) -> decltype(has_function_with_no_arg(std::forward<T>(obj), &T::func))
{
   obj.func();
}
 
template<typename T>
auto SomeFunction(T&& obj, int x) -> decltype(has_function_with_one_arg(std::forward<T>(obj), &T::func))
{
   obj.func(x);
}
 
struct A
{
   void func()
   {
      std::cout << "func" << std::endl;
   }
};
 
struct B
{
   void func(int x)
   {
      std::cout << "func(int)" << std::endl;
   }
};
 
int main()
{
   SomeFunction(A(), 1);
   SomeFunction(B(), 1);
}
Добавлено через 12 минут
Ну и конечно можно без усложнений.

C++
1
2
3
4
5
6
7
8
9
10
11
template<typename T>
auto SomeFunction(T&& obj, int) -> decltype(obj.func(), void())
{
   obj.func();
}
 
template<typename T>
auto SomeFunction(T&& obj, int x) -> decltype(obj.func(x), void())
{
   obj.func(x);
}
Однако в отличии от enable_if я не могу здесь придумать как сделать вариант данной функции с понятным сообщением ошибки для всех остальных случаев.
1
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
26.06.2014, 11:27  [ТС]
Проверил, все работает. Еще раз спасибо)
Если уж совсем обнахалиться, то вот еще какой вопрос...
Есть ли возможность написать функцию SomeFunction() таким образом, чтобы она в зависимости от типа принимала то одно то два значения, дабы не было в программе варнингов из-за лишних аргументов функции?
Чтобы вызов функции выглядел как:
SomeFunction(t, x);
Но для определенных типов t, второй параметр игнорировался бы и варнигов бы не было
Хотя... из области фантастики, врят-ли такое возможно)) Но помечтать то можно))
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.06.2014, 11:35
Variag, Так он ведь итак игнорируется в тех примерах которые вам давали. Дабы перестали быть ворнинги просто уберите имя переменной в функции, которая ее не использует.
1
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
26.06.2014, 11:41  [ТС]
Точно) Просто привык имя переменной всегда писать))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.06.2014, 11:41
Помогаю со студенческими работами здесь

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

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

Ошибка С1083 при компиляции кода
#include &lt;stdio.h&gt; #include &lt;math.h&gt; #include &lt;conio.h&gt; #include &quot;stdafx.h&quot; #include&lt;windows.h&gt; int main() { double x,...

Ошибки C2678 и C2679 при компиляции кода
#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; ...

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru