AUTOSAR C++14 Rule A8-4-6

"передайте" параметры, объявленные, как T && должен всегда передаваться

Описание

Управляйте определением

"передайте" параметры, объявленные, как T && должен всегда передаваться.

Объяснение

Поскольку rvalue ссылки не могут связать с lvalues, функции, которые включают использование семантики перемещения при помощи rvalue ссылок в их подписи, не принимают lvalues. Этот вопрос решен при помощи rvalue ссылки на текстовый объект шаблона nonconst, который называется "прямым" параметром. Эти параметры могут связать и с rvalues и с lvalues при сохранении их проверок cv и категорий значения. "Прямые" параметры полезны, когда это необходимо, чтобы передать значение целевому объекту или функции при помощи функционального std::forward.

Когда вы объявите шаблон функции при помощи "Прямого" параметра, не используйте параметр ни в каких операциях. Поскольку "Прямые" параметры могут связать и с lvalues и с rvalues, использование их в операции может повредить их проверки cv и категории значения. Передайте эти параметры непосредственно месту назначения при помощи std::forward не используя их в операции.

Реализация Polyspace

Polyspace® отмечает "Прямой" параметр в определении шаблона функции или Лямбда-выражения, если какое-либо из этих условий верно:

  • "Прямой" параметр не передается месту назначения при помощи std::forward.

  • Операция кроме передачи выполняется на "Прямом" параметре или на объекте члена его.

Polyspace игнорирует шаблоны и Лямбда-выражения, которые остаются неиспользованными в вашем коде.

Поиск и устранение проблем

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

развернуть все

#include<string>
#include<vector>
#include <iostream>

struct intWrapper {
	intWrapper(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
	intWrapper(int& n)  { std::cout << "lvalue overload, n=" << n << "\n"; }
};
struct floatWrapper {
	floatWrapper(double&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
	floatWrapper(double& n)  { std::cout << "lvalue overload, n=" << n << "\n"; }
};

class mixedNumerical {
public:
	template<class T1, class T2, class T3>
	mixedNumerical(T1&& t1, T2&& t2, T3&& t3) :   //violation on T3    
	a1_{std::forward<T1>(t1)},
	a2_{std::forward<T2>(t2)},
	a3_{std::forward<T3>(t3)}
	{
	}

private:
	intWrapper a1_, a2_;
	floatWrapper	a3_;
};


template<class T, class... U>
std::unique_ptr<T> unique_ptr_factory(U&&... u)
{
	return std::unique_ptr<T>(new T(std::forward<U>(u)...));    
}

int main()
{
	auto p1 = unique_ptr_factory<intWrapper>(2); // rvalue
	int i = 1;
	auto p2 = unique_ptr_factory<intWrapper>(i); // lvalue

	std::cout << "mixedNumerical\n";
	double lvalue = 2.2;
	auto t = unique_ptr_factory<mixedNumerical>(2, i, 2.2);// rvalue
	auto t2 = unique_ptr_factory<mixedNumerical>(2, i, lvalue);// lvalue
}


Этот пример показывает реализацию гибкого интерфейса к функциональному unique_ptr_factory при помощи "прямого" пакета параметра. Эта функция принимает "прямой" пакет параметра, и затем вперед параметры их соответствующим конструкторам при помощи std::forward. Конструкторы перегружаются, чтобы принять и rvalues и lvalues. В результате функциональный unique_ptr_factory производит unique_ptr к intWrapper текстовые объекты и mixedNumerical текстовые объекты при требовании минимальной перегрузки. Это использование "форварда" совместимо с этим правилом, потому что "прямые" параметры передаются своему месту назначения при помощи std::forward. Поскольку никакая другая операция не выполняется на них, их категории проверки и значения cv сохраняются.

#include<string>
#include<vector>
void task(int i);
template<typename T>
T NoncompliantTemplate(T&& arg)    // Noncompliant
{
	return arg;       // Noncompliant
}

auto NoncompliantLambda = [](auto&& truc) {    // Noncompliant
	return truc;                         // Noncompliant
};
template<typename T>
T ReturnStaticCast(int&& i) //Compliant: not a template parameter.
{
	return static_cast<T>(i);
}
template<typename T>
void ConstArg(const T&& t)      // Compliant: const
{}

template<typename T>
void UnusedArg(T&& t)              // Noncompliant
{}

template<typename T>
void UnnamedArg(T&& )              // Noncompliant
{}
template<typename T>
void usage(T&& t1, T&& t2)
{
	if (t1==t2)                       // Noncompliant
	{
		task(std::forward<T>(t1));
	}
	else
	{
		task(std::forward<T>(t1));
		task(std::forward<T>(t2));
	}
}
class intWrapper
{
public:
	int m;
};

template<typename T>
void CheckForward(T&& t)
{
	if (t.m != 0)                        // Noncompliant
	{
		UnusedArg(std::forward<T>(t));
	}
}
auto CompliantLambda = [](auto&& truc) {    // Compliant
	return NoncompliantLambda(std::forward<decltype(truc)>(truc));
};
template<typename T>
T NoninstantiatedTemplate(T&& arg)    // Not checked
{
	return arg;       // Not checked
}
void foo(){
	int i;
	intWrapper C;
	C.m = i;
	NoncompliantTemplate(i);
	CheckForward(std::move(C));
	usage(i,C.m);
	UnnamedArg(i);
	CompliantLambda(i);
}

Этот пример показывает использование "прямых" параметров, которые несовместимы с этим правилом.

  • Polyspace отмечает nonconst T&& параметр arg из шаблона NoncompliantTemplate потому что этот "прямой" параметр не передается месту назначения при помощи std::forward. Параметр отмечается в объявлении и операторе возврата.

  • Polyspace отмечает nonconst auto&& параметр truc из Лямбда-выражения NoncompliantLambda потому что этот "прямой" параметр не передается месту назначения при помощи std::forward. Параметр отмечается в объявлении и операторе возврата.

  • Polyspace не делает флага int&& аргумент i из шаблона ReturnStaticCast потому что этот аргумент не является типом шаблона nonconst rvalue ссылка. По той же причине Polyspace не отмечает аргумент ConstArg.

  • Polyspace отмечает тип шаблона nonconst rvalue ссылочный аргумент t из шаблона UnusedArg потому что этот "прямой" параметр не передается месту назначения при помощи std::forward.

  • Polyspace отмечает аргумент шаблона UnnamedArg потому что "прямой" параметр без имени, и он не может быть передан при помощи std::forward.

  • Polyspace отмечает параметры t1 и t2 в операторе if (t1==t2) в шаблоне usage потому что эти "прямые" параметры используются в операции, прежде чем они будут переданы при помощи std::forward. Это средство проверки также повышено на t в операторе if (t.m != 0) в шаблоне CheckForward потому что член "прямого" параметра t получен доступ.

  • Polyspace не проверяет шаблон NoninstantiatedTemplate потому что этот шаблон не использован в коде.

Проверяйте информацию

Группа: операторы объявления
Категория: необходимый, автоматизированный
Введенный в R2021a