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

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

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

Author24 — интернет-сервис помощи студентам
Здравствуйте!
Столкнулся с почти аналогичной проблемой, как и описанная в данной статье:
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
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.06.2014, 13:47
Ответы с готовыми решениями:

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

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

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

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

19
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 13:54 2
Если в зависимости от типа нужно выполнять определенный код, то просто специализируй шаблон функции. Безо всяких if внутри.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 13:56  [ТС] 3
Я бы так и сделал, если бы, типов было только 2, но их несколько побольше и для каждого специализацию писать лениво)))
Но в конце концов я так и сделаю, если иного решения не найдется))
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 13:59 4
Цитата Сообщение от Variag Посмотреть сообщение
и для каждого специализацию писать лениво)))
А в чем разница-то? Ты тут так же будешь для каждого типа будешь писать свой if.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
24.06.2014, 14:04  [ТС] 5
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point. Признак писать короче чем специализацию для каждого типа)
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.06.2014, 14:18 6
Цитата Сообщение от Variag Посмотреть сообщение
а так я их разделю по общему признаку на основе <type_traits> типа std::is_integral или std::is_floating_point
Это уже уточнение. Тогда да, короче.
0
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
25.06.2014, 11:28  [ТС] 7
Ну а все-таки) Неужели никто не знаком в достаточной мере с программированием шаблонов?))
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
25.06.2014, 11:30 8
Variag, ты вопрос задай по-нормальному. Не понятно, что тебе нужно. Написал ты свой пример того, как собираешься делать. И в чем вопрос-то? Чем тебя твой "алгоритм" конкретно не устраивает?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
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
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
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
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
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
What a waste!
1608 / 1300 / 180
Регистрация: 21.04.2012
Сообщений: 2,729
26.06.2014, 00:25 13
Лучший ответ Сообщение было отмечено 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
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,270
26.06.2014, 04:13 14
Лучший ответ Сообщение было отмечено 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  [ТС] 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
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
26.06.2014, 10:28 16
Цитата Сообщение от 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
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.06.2014, 11:01 17
В С++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  [ТС] 18
Проверил, все работает. Еще раз спасибо)
Если уж совсем обнахалиться, то вот еще какой вопрос...
Есть ли возможность написать функцию SomeFunction() таким образом, чтобы она в зависимости от типа принимала то одно то два значения, дабы не было в программе варнингов из-за лишних аргументов функции?
Чтобы вызов функции выглядел как:
SomeFunction(t, x);
Но для определенных типов t, второй параметр игнорировался бы и варнигов бы не было
Хотя... из области фантастики, врят-ли такое возможно)) Но помечтать то можно))
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
26.06.2014, 11:35 19
Variag, Так он ведь итак игнорируется в тех примерах которые вам давали. Дабы перестали быть ворнинги просто уберите имя переменной в функции, которая ее не использует.
1
1 / 1 / 0
Регистрация: 21.10.2011
Сообщений: 24
Записей в блоге: 1
26.06.2014, 11:41  [ТС] 20
Точно) Просто привык имя переменной всегда писать))
0
26.06.2014, 11:41
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.06.2014, 11:41
Помогаю со студенческими работами здесь

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

Ошибка С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;...

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

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


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru