Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519

Gtest, доступ к элементам базового класса-шаблона без указания параметров шаблона. баг или фича?

18.05.2019, 20:39. Показов 1459. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет.

Продолжаю экспертизу gtest/gmock.

Количество ошибок и багов зашкаливает.

Ничего удивительного, учитывая то,
как плохо они тестирует собственный фреймворк для тестов.
У них всего два сервиса: на одном тестируется сборка gcc,
на другом - вижуал студия.

О том, что бы тестировать для всех заявленных платформ,
всеми заявленными компиляторами и речи не идет.

В результате, о возникающих проблемах они узнают
в лучшем случае от "сознательных" граждан,
что пишут гневные баг-репорты,
и шлют им пулл-реквесты.

И вот, похоже, что теперь такая порочная практика привела к новой проблеме:
Нарушения легаси.

Фреймворк перестал собираться на старых линейках вижуал студии.

Следующий код иллюстрирует проблему:

https://rextester.com/FKX1017

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
 
template<class t> 
struct first
{
    using type = t;
};
 
template<class t> 
struct next : first<t>
{
    using type = typename next::first::type;
    
    type val = 333;
};
 
int main()
{
    next<int> sample;
    
    std::cout << "val = " << sample.val << '\n';
}
output:
Code
1
val = 333
Код прекрасно собирается и работает.
Не только gcc, но и новыми компиляторами от Visual Studio
Например, компилятор от Visual Studio 2015 update 3

Однако, вот эта строка немножко напрягает:
C++
1
using type = typename next::first::type;
Что об этом говорит стандарт языка?
С каких это пор можно обращаться к элементам шаблонно-класса,
без указания параметров шаблона?

Всегда думала, что опускать параметры шаблона класса
можно только для методов этого же класса.

Похоже, что более старые компиляторы (Visual Studio 2015 update 1)
рассуждают так же, как и я:

https://rextester.com/ACJ53272

Code
1
2
3
source_file.cpp(13): error C2039: 'first<int>': is not a member of 'next<int>'
source_file.cpp(20): note: see reference to class template instantiation 'next<int>' being compiled
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
Привожу код к более каноничному виду, и сборка завершается успехом:

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
#include <iostream>
 
template<class t>
struct first
{
    using type = t;
};
 
 
template<class t>
struct next : first<t>
{
    using base = first<t>;
    using type = typename base::type;
    
    type val = 333;
};
 
int main()
{
    next<int> sample;
    
    std::cout << "val = " << sample.val << '\n';
}
Учитывая, что gtest прекрасно собирался и работал
на всей линейке студий начиная с 2008 (а может и 2003?)
Можно сделать неутешительный вывод:
поддержка фреймворка никакая.
за качество никто не отвечает.
количество багов растет.
качество кода - падает.
использование - на свой страх и риск.
и этот страх более чем обоснован.

фрагменты реального проблемного кода


файл: gtest-internal.h

https://rextester.com/OXKC11289

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
 
// Backport of std::index_sequence.
template <size_t... Is>
struct IndexSequence {
  using type = IndexSequence;
};
 
// Double the IndexSequence, and one if plus_one is true.
template <bool plus_one, typename T, size_t sizeofT>
struct DoubleSequence;
template <size_t... I, size_t sizeofT>
struct DoubleSequence<true, IndexSequence<I...>, sizeofT> {
  using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>;
};
template <size_t... I, size_t sizeofT>
struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
  using type = IndexSequence<I..., (sizeofT + I)...>;
};
 
// Backport of std::make_index_sequence.
// It uses O(ln(N)) instantiation depth.
template <size_t N>
struct MakeIndexSequence
    : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type,
                     N / 2>::type {};
 
template <>
struct MakeIndexSequence<0> : IndexSequence<> {};
 
// FIXME: This implementation of ElemFromList is O(1) in instantiation depth,
// but it is O(N^2) in total instantiations. Not sure if this is the best
// tradeoff, as it will make it somewhat slow to compile.
template <typename T, size_t, size_t>
struct ElemFromListImpl {};
 
template <typename T, size_t I>
struct ElemFromListImpl<T, I, I> {
  using type = T;
};
 
// Get the Nth element from T...
// It uses O(1) instantiation depth.
template <size_t N, typename I, typename... T>
struct ElemFromList;
 
template <size_t N, size_t... I, typename... T>
struct ElemFromList<N, IndexSequence<I...>, T...>
    : ElemFromListImpl<T, N, I>... {};
 
template <typename... T>
class FlatTuple;
 
template <typename Derived, size_t I>
struct FlatTupleElemBase;
 
template <typename... T, size_t I>
struct FlatTupleElemBase<FlatTuple<T...>, I> {
  using value_type =
      typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type,
                            T...>::type;
  FlatTupleElemBase() = default;
  explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {}
  value_type value;
};
 
template <typename Derived, typename Idx>
struct FlatTupleBase;
 
template <size_t... Idx, typename... T>
struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>>
    : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
  using Indices = IndexSequence<Idx...>;
  FlatTupleBase() = default;
  explicit FlatTupleBase(T... t)
      : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {}
};
 
// Analog to std::tuple but with different tradeoffs.
// This class minimizes the template instantiation depth, thus allowing more
// elements that std::tuple would. std::tuple has been seen to require an
// instantiation depth of more than 10x the number of elements in some
// implementations.
// FlatTuple and ElemFromList are not recursive and have a fixed depth
// regardless of T...
// MakeIndexSequence, on the other hand, it is recursive but with an
// instantiation depth of O(ln(N)).
template <typename... T>
class FlatTuple: private FlatTupleBase<FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type> 
{
  using Indices = typename FlatTuple::FlatTupleBase::Indices;
 
 public:
  FlatTuple() = default;
  explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {}
 
  template <size_t I>
  const typename ElemFromList<I, Indices, T...>::type& Get() const {
    return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value;
  }
 
  template <size_t I>
  typename ElemFromList<I, Indices, T...>::type& Get() {
    return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value;
  }
};
 
int main()
{
    using type = FlatTuple<bool, bool>;
    
    type val(true, true);
    (void)val;
}
В качестве ремонта, я заменяю фрагмент:
C++
1
using Indices = typename FlatTuple::FlatTupleBase::Indices;
На:
C++
1
2
  using Base = FlatTupleBase<FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type>;
  using Indices = typename Base::Indices;
И сборка проходит успешно:

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
 
// Backport of std::index_sequence.
template <size_t... Is>
struct IndexSequence {
  using type = IndexSequence;
};
 
// Double the IndexSequence, and one if plus_one is true.
template <bool plus_one, typename T, size_t sizeofT>
struct DoubleSequence;
template <size_t... I, size_t sizeofT>
struct DoubleSequence<true, IndexSequence<I...>, sizeofT> {
  using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>;
};
template <size_t... I, size_t sizeofT>
struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
  using type = IndexSequence<I..., (sizeofT + I)...>;
};
 
// Backport of std::make_index_sequence.
// It uses O(ln(N)) instantiation depth.
template <size_t N>
struct MakeIndexSequence
    : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type,
                     N / 2>::type {};
 
template <>
struct MakeIndexSequence<0> : IndexSequence<> {};
 
// FIXME: This implementation of ElemFromList is O(1) in instantiation depth,
// but it is O(N^2) in total instantiations. Not sure if this is the best
// tradeoff, as it will make it somewhat slow to compile.
template <typename T, size_t, size_t>
struct ElemFromListImpl {};
 
template <typename T, size_t I>
struct ElemFromListImpl<T, I, I> {
  using type = T;
};
 
// Get the Nth element from T...
// It uses O(1) instantiation depth.
template <size_t N, typename I, typename... T>
struct ElemFromList;
 
template <size_t N, size_t... I, typename... T>
struct ElemFromList<N, IndexSequence<I...>, T...>
    : ElemFromListImpl<T, N, I>... {};
 
template <typename... T>
class FlatTuple;
 
template <typename Derived, size_t I>
struct FlatTupleElemBase;
 
template <typename... T, size_t I>
struct FlatTupleElemBase<FlatTuple<T...>, I> {
  using value_type =
      typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type,
                            T...>::type;
  FlatTupleElemBase() = default;
  explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {}
  value_type value;
};
 
template <typename Derived, typename Idx>
struct FlatTupleBase;
 
template <size_t... Idx, typename... T>
struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>>
    : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
  using Indices = IndexSequence<Idx...>;
  FlatTupleBase() = default;
  explicit FlatTupleBase(T... t)
      : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {}
};
 
// Analog to std::tuple but with different tradeoffs.
// This class minimizes the template instantiation depth, thus allowing more
// elements that std::tuple would. std::tuple has been seen to require an
// instantiation depth of more than 10x the number of elements in some
// implementations.
// FlatTuple and ElemFromList are not recursive and have a fixed depth
// regardless of T...
// MakeIndexSequence, on the other hand, it is recursive but with an
// instantiation depth of O(ln(N)).
template <typename... T>
class FlatTuple: private FlatTupleBase<FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type> 
{
  using Base = FlatTupleBase<FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type>;
  using Indices = typename Base::Indices;
 
 public:
  FlatTuple() = default;
  explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {}
 
  template <size_t I>
  const typename ElemFromList<I, Indices, T...>::type& Get() const {
    return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value;
  }
 
  template <size_t I>
  typename ElemFromList<I, Indices, T...>::type& Get() {
    return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value;
  }
};
 
int main()
{
    using type = FlatTuple<bool, bool>;
    
    type val(true, true);
    (void)val;
}



По хорошему, нужно проверить всю линейку: 2008/2010/2012/2013/2015/2017/2019
И на различных компиляторах gcc/clang/etc
К сожалению, у меня нет таких ресурсов
Будет классно, если форумчане скачают фреймворк с офф-сайта,
выполнят сборку и запустят тесты, что идут в комплекте с фреймворком.
И отпишут в тему о результатах.
Так мы можем помочь этому замечательному фреймворку.

В настоящий момент у gtest проблема с компиляцией.
проблема с компиляций собственных тестов.
проблема с прохождением этих тестов.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.05.2019, 20:39
Ответы с готовыми решениями:

Определение метода-шаблона за пределами шаблона класса
День добрый! Разбираюсь в шаблонах, решил копнуть поглубже. Вот пример: template &lt;typename T1&gt; class K // шаблон класса { ...

Доступ к закрытым членам класса(шаблона)
Вопрос почему компилятор выдает ошибку в функции main? Ситуация следующая имеется шаблон (класс) элемента списка, реализован шаблон (класс)...

Баг или фича
решил проверить на своем VS 2008 присвоение в сравнении написал char buf; char *buf1; if(buf1=buf) все прошло никакого...

4
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
18.05.2019, 21:45
Цитата Сообщение от eva2326 Посмотреть сообщение
Так мы можем помочь этому замечательному фреймворку.
А чем замечателен фреймворк, у которого
Цитата Сообщение от eva2326 Посмотреть сообщение
Количество ошибок и багов зашкаливает.
?
0
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519
18.05.2019, 22:15  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
А чем замечателен фреймворк
Практичный: простота развертывания, и удобства "цивилизации".
При том, что гугло-тесты не прибиты гвоздями к какой то одной платформе.
И легко адаптируются к различным условиям.

Другие подобные фреймворки либо мало чего умеют,
либо прибиты гвоздями к какой то определенной платформе.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
18.05.2019, 22:25
А проблема тогда в чем? В двух словах
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
19.05.2019, 02:34
Цитата Сообщение от eva2326 Посмотреть сообщение
Что об этом говорит стандарт языка?
Цитата Сообщение от https://timsong-cpp.github.io/cppwp/n4659/temp.local#3
The injected-class-name of a class template or class template specialization can be used either as a template-name or a type-name wherever it is in scope. [ Example:

C++
1
2
3
4
5
6
7
template <class T> struct Base {
  Base* p;
};
 
template <class T> struct Derived: public Base<T> {
  typename Derived::Base* p;    // meaning Derived::Base<T>
};
Цитата Сообщение от eva2326 Посмотреть сообщение
С каких это пор можно обращаться к элементам шаблонно-класса,
без указания параметров шаблона?
С пор C++03.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.05.2019, 02:34
Помогаю со студенческими работами здесь

Баг или фича ? =)
Thread threads = new Thread; for (int i = 0; i &lt; threads.Length; i++) { threads = new...

Баг или фича?
Здраствуйте. Читая главу о локализации книги Гослинга, Арнольда, Холмса &quot;Язык программирования Java 3е издание&quot; (господи, люди, может...

Баг или фича?
Всем привет. Вот какая интересная штука происходит с жизненным циклом активити. Если выходить из приложения &quot;механической...

Баг или фича?
Как известно -1^2=1 и math.pow(-1,2) выдает верный результат, но -1 ** 2 выдает -1

Таймеры - баг или фича?
В общем, пробую код,как тут http://iosystm32.ru/for-bikymmirs/27-basic-timers Единственное, немного изменяю - перед запуском таймера...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru