Студия игнорирует 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.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Студия игнорирует ODR?!
От: wander  
Дата: 17.03.13 13:41
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Окей, разъясни тогда плз почему.

Потому что каждый *.cpp компилируется независимо исходя из доступной для него информации. Если ты не включил в него прототип своей функции, или саму функцию, или *.h с прототипом и т.п., то в получившемся объектнике будет использована та функция, которая была доступна (т.е. шаблонная). Компилятор не смотрит в соседние единицы трансляции.
Re[4]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 17.03.13 15:31
Оценка:
Здравствуйте, wander, Вы писали:

B>>Окей, разъясни тогда плз почему.

W>Потому что каждый *.cpp компилируется независимо исходя из доступной для него информации. Если ты не включил в него прототип своей функции, или саму функцию, или *.h с прототипом и т.п., то в получившемся объектнике будет использована та функция, которая была доступна (т.е. шаблонная). Компилятор не смотрит в соседние единицы трансляции.
Так и я об этом. В моем cpp-файле определена моя свободная функция. И она используется, если мой сpp-файл один. Если появлятся другие cpp-файлы, то в моем (!) cpp-файле эта свободная функция работать перестает.

Вот я и спрашиваю — какого х компилятор лезет в другие единицы трансляции и извлекает оттуда какие-то другие функции вместо моей?!
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[6]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 17.03.13 15:33
Оценка:
Здравствуйте, Vain, Вы писали:

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

V>Много хочешь. Выборка из набора функций проходит на этапе компиляции.
Тогда почему не работает?
В моем cpp-файле свободная функция определена. И она выбирается, если нет других cpp-файлов. Почему она перестает выбираться при появлении других cpp-файлов?! Ведь "выборка из набора функций проходит на этапе компиляции", а не линковки, так?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[7]: Студия игнорирует ODR?!
От: Vain Россия google.ru
Дата: 17.03.13 23:43
Оценка:
Здравствуйте, Basil2, Вы писали:

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

V>>Много хочешь. Выборка из набора функций проходит на этапе компиляции.
B>Тогда почему не работает?
B>В моем cpp-файле свободная функция определена. И она выбирается, если нет других cpp-файлов. Почему она перестает выбираться при появлении других cpp-файлов?!
Потому-что компилятор её "не видит" в других cpp-файлах. Чтобы увидел надо объявление поместить выше точки вызова во всех cpp-файлах.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[8]: Студия игнорирует ODR?!
От: Basil2 Россия https://starostin.msk.ru
Дата: 19.03.13 07:00
Оценка:
Здравствуйте, Vain, Вы писали:

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

V>>>Много хочешь. Выборка из набора функций проходит на этапе компиляции.
B>>Тогда почему не работает?
B>>В моем cpp-файле свободная функция определена. И она выбирается, если нет других cpp-файлов. Почему она перестает выбираться при появлении других cpp-файлов?!
V>Потому-что компилятор её "не видит" в других cpp-файлах. Чтобы увидел надо объявление поместить выше точки вызова во всех cpp-файлах.
Если он ее не видит, то почему он ее использует?!
В этом и проблема: компилятор использует — в моем файле — не мою функцию, а из другого cpp-файла. На Студию я, согласен, зря гнал — gcc также себя ведет. Просто наперво очень странным поведение показалось.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[9]: Студия игнорирует ODR?!
От: Vain Россия google.ru
Дата: 19.03.13 18:45
Оценка: 11 (2) +1
Здравствуйте, Basil2, Вы писали:

V>>Потому-что компилятор её "не видит" в других cpp-файлах. Чтобы увидел надо объявление поместить выше точки вызова во всех cpp-файлах.

B>Если он ее не видит, то почему он ее использует?!
B>В этом и проблема: компилятор использует — в моем файле — не мою функцию, а из другого cpp-файла.
Как он это может делать если ты сам сказал что её там нет?
К тому же это линкер решает использовать или нет, а вот какую — выбирает компилятор для каждого cpp-файла по отдельности. Отсюда One Definition Rule — если определение одной и той же функции присутствует более чем в одной единице трансляции (cpp-файле) то они обязаны быть одинаковыми. К примеру, инлайн функции во всех единицах трансляции обязаны совпадать.
Ты нарушаешь это правило удаляя часть функций (твою свободную функцию) т.к. она является частью одного большого определения функий с таким же именем (шаблон+твоя свободная функция) а это UB.
Если же тебе надо определение хранить в одном cpp-файле а использовать из разных, то надо как минимум объявить все функции до первого использования (исключение — шаблонная функция, её определение надо определять как и инлайн функцию — до первого использования).
Ты смешал первый способ со вторым, это не будет работать и я уже объяснил почему.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.