Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 13.03.13 09:53
Оценка: +1 -1
Использую Google Test. В нем определена функция

template <typename T>
void PrintTo(const T& value, ::std::ostream* os)
{ ... }

Чтобы распечатать свой тип, переопределяю ее:
inline void PrintTo(const MyType& value, ::std::ostream* os)
{ ... }

Итог:
Если gtest используется только в моем cpp-файле, все работает. Если gtest используется в нескольких файлах, то переопределение моей функции необходимо включить во все эти файлы! Если хотя бы в одном из этих файлов моя функция не определена, то она перестает вызываться (в моем cpp) и вместо нее используется шаблон.

Более того, даже если я убираю inline (и тогда использую функцию только в своем cpp-файле), все остается по-прежнему. Используется шаблон, а не моя свободная ф-ция. Какого х? Куда смотрит линкер?? Я так понимаю, по шаблону генерируются сигнатура, которая полностью совпадает с моей свободной функцией.

Два вопроса:
1. Почему это глотает линкер?
2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: Студия игнорирует ODR?!
От: K13 http://akvis.com
Дата: 13.03.13 10:17
Оценка:
B>Куда смотрит линкер?? Я так понимаю, по шаблону генерируются сигнатура, которая полностью совпадает с моей свободной функцией.

Неа.
если нет явной функции, вызывается PrintTo<MyType>(), сигнатура которой никак не совпадает с обычной функцией PrintTo()
Re: Студия игнорирует ODR?!
От: uzhas Ниоткуда  
Дата: 13.03.13 10:26
Оценка: :)
Здравствуйте, Basil2, Вы писали:

B>Использую Google Test.

быстро вы к нам вернулись отсюда http://rsdn.ru/forum/cpp.applied/5090608.flat
Автор: Basil2
Дата: 04.03.13


B>Два вопроса:

B>1. Почему это глотает линкер?
таковы правила, обычная и шаблонная функция для линкера выглядят разными

B>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)

надо запихать, таковы правила игры
Re[2]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 13.03.13 14:18
Оценка:
Здравствуйте, K13, Вы писали:

B>>Куда смотрит линкер?? Я так понимаю, по шаблону генерируются сигнатура, которая полностью совпадает с моей свободной функцией.


K13>Неа.

K13>если нет явной функции, вызывается PrintTo<MyType>(), сигнатура которой никак не совпадает с обычной функцией PrintTo()

Хорошо. Почему тогда в моем cpp-файле, где объявлена свободная функция, она игнорируется и используется шаблонная?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 13.03.13 14:23
Оценка:
Здравствуйте, uzhas, Вы писали:

B>>Использую Google Test.

U>быстро вы к нам вернулись отсюда http://rsdn.ru/forum/cpp.applied/5090608.flat
Автор: Basil2
Дата: 04.03.13



B>>Два вопроса:

B>>1. Почему это глотает линкер?
U>таковы правила, обычная и шаблонная функция для линкера выглядят разными
Ок.

B>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)

U>надо запихать, таковы правила игры
Хорошо. Почему тогда в моем cpp-файле, где объявлена свободная функция, она игнорируется и используется шаблонная?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: Студия игнорирует ODR?!
От: Кодт Россия  
Дата: 13.03.13 15:29
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Хорошо. Почему тогда в моем cpp-файле, где объявлена свободная функция, она игнорируется и используется шаблонная?


Если у тебя аргумент — не MyType, а какой-нибудь MyDerivedType или MyType volatile, то шаблонная лучше подходит.
http://liveworkspace.org/code/2EpCyA$1
Перекуём баги на фичи!
Re[4]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 13.03.13 15:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Basil2, Вы писали:


B>>Хорошо. Почему тогда в моем cpp-файле, где объявлена свободная функция, она игнорируется и используется шаблонная?


К>Если у тебя аргумент — не MyType, а какой-нибудь MyDerivedType или MyType volatile, то шаблонная лучше подходит.

К>http://liveworkspace.org/code/2EpCyA$1

Согласен (кстати, не знал насчет volatile). Но у меня именно MyType.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: Это вы игнорируете ODR
От: ononim  
Дата: 13.03.13 18:24
Оценка:
B>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)
как-нибудь так:
#define PrintTo MyPrintTo
inline void MyPrintTo(const MyType& value, ::std::ostream* os)
{ ... }
Как много веселых ребят, и все делают велосипед...
Re: Студия игнорирует ODR?!
От: Vain Россия google.ru
Дата: 13.03.13 19:00
Оценка:
Здравствуйте, Basil2, Вы писали:

B>[ccode]template <typename T>

B>Более того, даже если я убираю inline (и тогда использую функцию только в своем cpp-файле), все остается по-прежнему. Используется шаблон, а не моя свободная ф-ция. Какого х? Куда смотрит линкер??
Компилер смотрит на объявления функций выши точки вызова и видит только шаблонное объявление.

B>Два вопроса:

B>1. Почему это глотает линкер?
B>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)
Ну наверно объявить свободную функцию до вызова?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Это вы игнорируете ODR
От: Basil2 Россия https://starostin.msk.ru
Дата: 14.03.13 16:40
Оценка:
Здравствуйте, ononim, Вы писали:

B>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)

O>как-нибудь так:
O>
O>#define PrintTo MyPrintTo
O>inline void MyPrintTo(const MyType& value, ::std::ostream* os)
O>{ ... }
O>


Не очень понял — как отдельный дефайн поможет линкеру выбрать мою функцию?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[2]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 14.03.13 16:48
Оценка:
Здравствуйте, Vain, Вы писали:

V>Компилер смотрит на объявления функций выши точки вызова и видит только шаблонное объявление.


B>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)

V>Ну наверно объявить свободную функцию до вызова?

В том то и дело, что в моем файле я объявляю _до_ вызова. И это работает.

Но если в других файлах есть подобный вызов, то используется шаблон. Т.е. это разные единицы трансляции и, как я понимаю, в дело вступает линкер. И вот тут я понять его не могу.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: Студия игнорирует ODR?!
От: wander  
Дата: 14.03.13 17:27
Оценка:
Здравствуйте, Basil2, Вы писали:

B>1. Почему это глотает линкер?


Надо понять одну вещь: линкер тут не при чем.
Re[3]: Студия игнорирует ODR?!
От: Vain Россия google.ru
Дата: 14.03.13 21:06
Оценка:
Здравствуйте, Basil2, Вы писали:

V>>Компилер смотрит на объявления функций выши точки вызова и видит только шаблонное объявление.

B>>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)
V>>Ну наверно объявить свободную функцию до вызова?
B>В том то и дело, что в моем файле я объявляю _до_ вызова. И это работает.
B>Но если в других файлах есть подобный вызов, то используется шаблон.
А объявление где, до или после? И как я понимаю, ты уже сделал дамп препроцессора на таких файлах и убидился в этом?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 15.03.13 12:55
Оценка:
Здравствуйте, wander, Вы писали:

B>>1. Почему это глотает линкер?

W>Надо понять одну вещь: линкер тут не при чем.
Окей, разъясни тогда плз почему.
Если работа кода меняется при изменении в другой единицы трансляции, то кто за это отвечает?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[4]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 15.03.13 13:00
Оценка:
Здравствуйте, Vain, Вы писали:

V>>>Компилер смотрит на объявления функций выши точки вызова и видит только шаблонное объявление.

B>>>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)
V>>>Ну наверно объявить свободную функцию до вызова?
B>>В том то и дело, что в моем файле я объявляю _до_ вызова. И это работает.
B>>Но если в других файлах есть подобный вызов, то используется шаблон.
V>А объявление где, до или после? И как я понимаю, ты уже сделал дамп препроцессора на таких файлах и убидился в этом?
Объявление чего?

В моем cpp-файле, свою свободную функцию я объявляю до.
В других единицах трансляции я эту функцию либо не объявляю вовсе (тогда в моем файле перестает вызываться свободная), либо везде объявляю тоже до, и тогда все работает.

При этом я хочу, чтобы вызов свободной функции работал независимо от других единиц трансляции, что не требовалось подключать хидер с моей функцией во все существующие cpp-файлы. Не так уж многого ведь хочу?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[3]: Студия игнорирует ODR?!
От: k.o. Россия  
Дата: 15.03.13 13:39
Оценка: 15 (1) +1
Здравствуйте, Basil2, Вы писали:

B>Здравствуйте, uzhas, Вы писали:


B>>>2. Как сделать так, чтобы гарантированно вызывалась моя функция? (не запихивая хидер с нею во все cpp-шники)

U>>надо запихать, таковы правила игры
B>Хорошо. Почему тогда в моем cpp-файле, где объявлена свободная функция, она игнорируется и используется шаблонная?

Не копался во внутренностях gtest, но, судя по всему, обычное нарушение ODR.

1.cpp

template <class T>
void print(T t);

template <class T>
void gtest_assert(T t)
{
  print(t); // используем шаблон print<T>
}

void my_test1()
{
  MyType t;
  gtest_assert(t);
}


2.cpp

template <class T>
void print(T t);

template <class T>
void gtest_assert(T t)
{
  print(t); // используем print(MyType);
}

void print(MyType t);

void my_test2()
{
  MyType t;
  gtest_assert(t);
}


Таким образом, в разных единицах трансляции получаем разные определения gtest_assert<MyType>, если она заинлайнится, то в 1.cpp будет вызов print<T>, в 2.cpp — print(MyType), иначе, будет зависеть от того, какой вариант gtest_assert выберет линковщик. Кроме того, не забываем, что это вообще-то UB.
Re[4]: Студия игнорирует ODR?!
От: uzhas Ниоткуда  
Дата: 15.03.13 14:27
Оценка: :))
Здравствуйте, k.o., Вы писали:

KO>Не копался

почти год молчал, а мимо нарушения ODR не смог пройти
Re[4]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 15.03.13 15:32
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Таким образом, в разных единицах трансляции получаем разные определения gtest_assert<MyType>, если она заинлайнится, то в 1.cpp будет вызов print<T>, в 2.cpp — print(MyType), иначе, будет зависеть от того, какой вариант gtest_assert выберет линковщик.

Спасибо. Пожалуй что так и есть. То есть единственный вариант это включать везде?


KO>Кроме того, не забываем, что это вообще-то UB.

А не круто ли? Вроде ничего такого не делали, а тут сразу UB Хотя, ведь C++ же...
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
й вариант
Re[5]: Студия игнорирует ODR?!
От: k.o. Россия  
Дата: 15.03.13 15:55
Оценка: 10 (1)
Здравствуйте, Basil2, Вы писали:

B>Здравствуйте, k.o., Вы писали:


KO>>Таким образом, в разных единицах трансляции получаем разные определения gtest_assert<MyType>, если она заинлайнится, то в 1.cpp будет вызов print<T>, в 2.cpp — print(MyType), иначе, будет зависеть от того, какой вариант gtest_assert выберет линковщик.

B>Спасибо. Пожалуй что так и есть. То есть единственный вариант это включать везде?

В общем да. Можно вместо PrintTo переопределить operator<<, с одной стороны, никакой разницы нет, но, в отличие от PrintTo, operator<< не специфичен для gtest и его вполне можно декларировать в одном файле с MyType. Еще как вариант, поменять gtest, чтобы требовалась явная реализация всех таких операций.

KO>>Кроме того, не забываем, что это вообще-то UB.

B>А не круто ли? Вроде ничего такого не делали, а тут сразу UB Хотя, ведь C++ же...

ну так и в UB ничего такого нет
Re[5]: Студия игнорирует ODR?!
От: Vain Россия google.ru
Дата: 15.03.13 19:11
Оценка:
Здравствуйте, Basil2, Вы писали:

V>>А объявление где, до или после? И как я понимаю, ты уже сделал дамп препроцессора на таких файлах и убидился в этом?

B>Объявление чего?
твоей свободной функции

B>В моем cpp-файле, свою свободную функцию я объявляю до.

B>В других единицах трансляции я эту функцию либо не объявляю вовсе (тогда в моем файле перестает вызываться свободная), либо везде объявляю тоже до, и тогда все работает.
естественно

B>При этом я хочу, чтобы вызов свободной функции работал независимо от других единиц трансляции, что не требовалось подключать хидер с моей функцией во все существующие cpp-файлы. Не так уж многого ведь хочу?

Много хочешь. Выборка из набора функций проходит на этапе компиляции.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.