Перегрузка функций по их возвращаемому значению

Иван Володин
Иван Володин

Стандарт C++14 13.1/2:
"Function declarations that differ only in the return type cannot be overloaded"
Источник (stackoverflow)

"Перегрузка функций со списками аргументов одного типа лишь на основании возвращаемого типа недопустима"
Источник (docs.microsoft)

Суть конфликта:

#include <iostream>

int getOne() //Error E0311
{
	return 1;
}

float getOne() //Error E0311
{
	return 1.1;
}


int main()
{
	int intOne = getOne();
	float floatOne = getOne();

	std::cout << intOne << ' ' << floatOne; //Код не скомпилируется из-за ошибок, вывода не будет

	return 0;
}

Идея:

Вызывать функцию, итог которой ожидается в записи. Это выглядело бы так:

#include <iostream>

int getOne()
{
	return 1;
}

float getOne()
{
	return 1.1;
}


int main()
{
	int intOne = getOne(); //Ожидается int, вызываем функцию int getOne()
	float floatOne = getOne(); //Ожидается double, вызываем функцию double getOne()

	std::cout << intOne << ' ' << floatOne; //Должно вывести "1 1.1"

	return 0;
}

Контр-аргумент:

Как тогда программа должна вести себя, если в записи не ожидается типа? Например:

getOne();
auto one = getOne();
std::cout << getOne();

В подобных случаях, нужно обозначить основную функцию - ту из перегрузок, которая будет вызываться в случае неопределенности. 

Предлагаемые варианты обозначения основных функций:
1) Использование оператора final при инициализации. Пример:

#include <iostream>

final int getOne()
{
	return 1;
}

float getOne()
{
	return 1.1;
}


int main()
{
	std::cout << getOne(); //Должно вывести "1"

	return 0;
}

(В случае, если конкретно final использоваться не может, можно также использовать public или override, или же, ввести новый термин для этой цели, например original, universal или standart)

2) Самая первая инициализированная - и есть основная. Примеры:

#include <iostream>

int getOne()
{
	return 1;
}

float getOne()
{
	return 1.1;
}


int main()
{
	std::cout << getOne(); //Должно вывести "1"

	return 0;
}
#include <iostream>

float getOne()
{
	return 1.1;
}

int getOne()
{
	return 1;
}


int main()
{
	std::cout << getOne(); //Должно вывести "1.1"

	return 0;
}

Распостраненные частичные или полные обходные решения проблемы в нынешнем C++:

1) Указание возвращаемого значения внутри имени функции. Пример:

#include <iostream>

int getOneInt()
{
	return 1;
}

float getOneFloat()
{
	return 1.1;
}


int main()
{
	int intOne = getOneInt();
	float floatOne= getOneFloat();

	std::cout << intOne << ' ' << floatOne; //Должно вывести "1 1.1"

	return 0;
}

2) Использование template для явного указания ожидаемого типа. (Источник) Например:

#include <iostream>

template<typename T> T getOne();

template<> int getOne()
{
	return 1;
}

template<> float getOne()
{
	return 1.1;
}


int main()
{
	int intOne = getOne<int>();
	float floatOne = getOne<float>();

	std::cout << intOne << ' ' << floatOne; //Должно вывести "1 1.1"

	return 0;
}

3) Переименование функций-перегрузок, чтобы создать перегружаемый структуру-функтор с именем функции. (Источник) Например:

#include <iostream>

template<typename T> T getOneFoo();

template<> int getOneFoo()
{
	return 1;
}

template<> float getOneFoo()
{
	return 1.1;
}

struct getOne //Структура-Функтор
{
	getOne() {}

	template<typename T> operator T()
	{
		return getOneFoo<T>();
	}
};



int main()
{
	int intOne = getOne();
	float floatOne = getOne();

	std::cout << intOne << ' ' << floatOne; //Должно вывести "1 1.1"

	return 0;
}

 

-11
рейтинг
2 комментария
HedgehogInTheCPP

сломает auto.

auto val = foo();

 перестанет компилироваться.

HedgehogInTheCPP
Обновлено 
Дмитрий

HedgehogInTheCPP, не перестанет, если допустить подобный вариант для случая отсутствия перегрузок.

Дмитрий
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения