exponenta event banner

Правило AUTOSAR C++ 14 A8-4-6

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

Описание

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

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

Объяснение

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

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

Внедрение Polyspace

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

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

  • Операция, отличная от пересылки, выполняется для параметра «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 с использованием пакета параметров «forward». Эта функция принимает пакет параметров «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);
}

В этом примере показано использование параметров «forward», которые не соответствуют этому правилу.

  • Polyspace помечает неконст T&& параметр arg шаблона NoncompliantTemplate поскольку этот параметр «forward» не пересылается адресату с помощью std::forward. Параметр помечается в объявлении и инструкции return.

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

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

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

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

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

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

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

Группа: Деклараторы
Категория: Обязательно, Автоматизировано
Представлен в R2021a