Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
874 / 332 / 76
Регистрация: 17.05.2015
Сообщений: 1,020
1

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

18.05.2019, 20:39. Просмотров 743. Ответов 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:
Код
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

Код
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
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.05.2019, 20:39
Ответы с готовыми решениями:

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

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

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

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

4
6406 / 4302 / 1740
Регистрация: 07.05.2019
Сообщений: 13,130
Записей в блоге: 1
18.05.2019, 21:45 2
Цитата Сообщение от eva2326 Посмотреть сообщение
Так мы можем помочь этому замечательному фреймворку.
А чем замечателен фреймворк, у которого
Цитата Сообщение от eva2326 Посмотреть сообщение
Количество ошибок и багов зашкаливает.
?
0
874 / 332 / 76
Регистрация: 17.05.2015
Сообщений: 1,020
18.05.2019, 22:15  [ТС] 3
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
А чем замечателен фреймворк
Практичный: простота развертывания, и удобства "цивилизации".
При том, что гугло-тесты не прибиты гвоздями к какой то одной платформе.
И легко адаптируются к различным условиям.

Другие подобные фреймворки либо мало чего умеют,
либо прибиты гвоздями к какой то определенной платформе.
0
6406 / 4302 / 1740
Регистрация: 07.05.2019
Сообщений: 13,130
Записей в блоге: 1
18.05.2019, 22:25 4
А проблема тогда в чем? В двух словах
0
284 / 175 / 21
Регистрация: 16.02.2018
Сообщений: 666
19.05.2019, 02:34 5
Цитата Сообщение от 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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.05.2019, 02:34

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

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

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

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

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


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

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

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