AUTOSAR C++14 Rule A8-4-6

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

Описание

Определение правила

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

Объяснение

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

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

Реализация Polyspace

Polyspace® помечает параметр «Forward» в определении шаблона функции или выражения Лямбды, если любое из следующих условий верно:

  • Параметр «Forward» не пересылается адресату при помощи std::forward.

  • Операция, отличная от переадресации, выполняется по параметру «Forward» или по представителю его объекта.

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

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

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

#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 при помощи пакета параметров «forward». Эта функция принимает пакет параметров «вперед», а затем пересылает параметры своим соответствующим конструкторам при помощи std::forward. Конструкторы перегружены, чтобы принять как rvalues, так и lvalues. В результате функция unique_ptr_factory производит unique_ptr на intWrapper вводить объекты и mixedNumerical вводить объекты, требуя минимальной перегрузки. Это использование «forward» соответствует этому правилу, потому что параметры «forward» передаются в их пункт назначения при помощи 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 помечает неконстатные T&& параметрический arg шаблона NoncompliantTemplate поскольку этот параметр «forward» не пересылается адресату при помощи std::forward. Параметр помечен в объявлении и операторе возврата.

  • Polyspace помечает неконстатные auto&& параметрический truc выражения Lambda NoncompliantLambda поскольку этот параметр «forward» не пересылается адресату при помощи std::forward. Параметр помечен в объявлении и операторе возврата.

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

  • Polyspace помечает неконстатный тип шаблона rvalue reference t шаблона UnusedArg поскольку этот параметр «forward» не пересылается адресату при помощи std::forward.

  • Polyspace помечает аргумент шаблона UnnamedArg поскольку параметр «forward» не называется и его нельзя переадресовать при помощи std::forward.

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

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

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

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