10.9. Роздільна здатність імен у визначеннях шаблонів А
10.9. Роздільна здатність імен у визначеннях шаблонів А
Усередині визначення шаблону сенс деяких конструкцій може різнитися залежно від конкретизації, тоді як зміст інших завжди залишається незмінним. Головну роль відіграє наявність у конструкції формального параметра шаблону:
template typename Type
Type min (Type * array, int size)
Type min_val = array [0];
for (int i = 1; i size; ++i)
if (array[i] min_val)
print("Minimum value found:");
У функції min() типи змінних array та min_val залежать від фактичного типу, яким буде замінено Type при конкретизації шаблону, тоді як тип змінної size залишиться int за будь-якого типу параметра шаблону. Отже, типи array та min_val у різних конкретизаціях різні. Тому говоримо, що типи цих змінних залежить від параметра шаблону, тоді як тип size від цього залежить.
Так як тип min_val невідомий, то невідома і операція, яка буде використовуватися з появою min_val у виразі. Наприклад, яка функція print() буде викликана під час звернення print(min_val)? Із типом аргументу int? Або float? Чи буде виклик помилковим, оскільки немає функції, яка може бути викликана з аргументом того ж типу, що і min_val? Зважаючи на це, ми говоримо, що й виклик print(min_val) залежить від параметра шаблону.
Такі питання не виникають для конструкцій всередині min(), які не залежать від параметрів шаблону. Наприклад, завжди відомо, яка функція має бути викликана для print("Minimum value found:"). Це функція друку рядків символів. У цьому випадку print() залишається однією і тією ж за будь-якої конкретизації шаблону, тобто не залежить від його параметрів.
У розділі 7 ми бачили, що у C++ функція має бутиоголошено до її виклику. Чи потрібно оголошувати функцію, що викликається всередині шаблону, перш ніж компілятор побачить його визначення? Чи маємо ми оголосити функцію print() у попередньому прикладі до визначення шаблону min()? Відповідь залежить від особливостей імені, на яке ми посилаємось. Конструкцію, яка залежить від параметрів шаблону, слід оголосити перед її використанням у шаблоні. Наведене вище визначення шаблону функції min() некоректне. Оскільки виклик
print("Minimum value found:");
// всередині min() викликається print(const char *)
void print (const char *);
template typename Type
Type min (Type * array, int size)
print("Minimum value found:");
Коли ж має бути оголошено функцію print(), що викликається під час звернення print(min_val)? До конкретизації шаблону. Наприклад:
int size = sizeof(ai)/sizeof(int);
// конкретизується min( int*, int )
main() викликає конкретизовану із шаблону функцію min(int*,int). У цьому реалізації Type замінено int, і тип змінної min_val, отже, дорівнює int. Тому, при зверненні print(min_val) викликається функція з аргументом типу int. Саме тоді, коли конкретизується min(int*,int) стає відомо, що при другому викликі аргумент print() має тип int. У цей момент така функція має бути видимою. Якби функція print(int) була оголошена до конкретизації min(int*,int), то компілятор видав повідомлення про помилку.
Тому роздільна здатність імен у визначенні шаблону відбувається у два етапи. Спочатку дозволяються імена, які залежать від його параметрів, та був, при конкретизації, – імена, залежні від параметрів.
Але навіщо потрібні два кроки? Чому б, наприклад, не дозволяти всі імена під час конкретизації?
template typename Type
Type min (Type * array, int size)
Type min_val = array [0];
// помилка: функцію print( const char* ) не знайдено