メインコンテンツ

AUTOSAR C++14 Rule A8-4-6

"forward" parameters declared as T && shall always be forwarded

R2021a 以降

説明

ルール定義

"forward" parameters declared as T && shall always be forwarded.

根拠

rvalue 参照は lvalue にバインドできないので、関数シグネチャで rvalue 参照を使用して移動セマンティクスを使用可能にしている関数では lvalue を受け入れません。この問題は、非定数テンプレート型オブジェクトへの rvalue 参照を使用して解決されます。これは "forward" パラメーターと呼ばれます。このパラメーターは、cv 修飾と value カテゴリを維持したまま rvalue と lvalue の両方にバインドできます。"forward" パラメーターは、関数 std::forward を使用して値を宛先オブジェクトまたは関数に転送する場合に役立ちます。

"forward" パラメーターを使用して関数テンプレートを宣言するときは、どの演算であってもこのパラメーターを使用しないでください。"forward" パラメーターは lvalue と rvalue のどちらにもバインドできるので、演算で使用すると cv 修飾と value カテゴリが破損する可能性があります。これらのパラメーターは、演算で使用せずに std::forward を使用して宛先に直接転送します。

Polyspace 実装

Polyspace® は、以下のいずれかの条件を満たす場合、関数テンプレートの定義またはラムダ式の "forward" パラメーターにフラグを設定します。

  • "forward" パラメーターが std::forward を使用して宛先に転送されない。

  • "forward" パラメーターまたはそのメンバー オブジェクトに対して転送以外の演算が実行される。

Polyspace は、コード内で使用されないままのテンプレートまたはラムダ式については無視します。

トラブルシューティング

ルール違反が想定されるものの、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
}


この例では、"forward" パラメーター パックを使用した関数 unique_ptr_factory へのフレキシブル インターフェイスの実装を示します。この関数は "forward" パラメーター パックを受け入れ、std::forward を使用してこれらのパラメーターを各コンストラクターに転送します。コンストラクターは、rvalue と lvalue の両方を受け入れるためオーバーロードされています。結果として、関数 unique_ptr_factory は必要なオーバーロードを最小限にしながら、intWrapper 型オブジェクトと mixedNumerical 型オブジェクトへの unique_ptr を生成します。この "forward" の使用はこのルールに準拠しています。"forward" パラメーターは std::forward を使用して宛先に転送されているからです。これらに対して他の演算は行われていないので、cv 修飾と value カテゴリは維持されます。

#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 は、テンプレート NoncompliantTemplate の非定数 T&& パラメーター arg にフラグを設定します。この "forward" パラメーターは std::forward を使用して宛先に転送されていないからです。このパラメーターには、宣言および return ステートメントでフラグが設定されます。

  • Polyspace は、ラムダ式 NoncompliantLambda の非定数 auto&& パラメーター truc にフラグを設定します。この "forward" パラメーターは std::forward を使用して宛先に転送されていないからです。このパラメーターには、宣言および return ステートメントでフラグが設定されます。

  • Polyspace は、テンプレート ReturnStaticCastint&& 引数 i にフラグを設定しません。この引数は非定数テンプレート型 rvalue 参照ではないからです。同じ理由で、Polyspace は ConstArg の引数にフラグを設定しません。

  • Polyspace は、テンプレート UnusedArg の非定数テンプレート型 rvalue 参照引数 t にフラグを設定します。この "forward" パラメーターは std::forward を使用して宛先に転送されていないからです。

  • Polyspace は、テンプレート UnnamedArg の引数にフラグを設定します。"forward" パラメーターが無名で、std::forward を使用して転送できないからです。

  • Polyspace は、テンプレート usage のステートメント if (t1==t2) のパラメーター t1t2 にフラグを設定します。これらの "forward" パラメーターは std::forward を使用して転送される前に演算で使用されているからです。このチェッカーは、テンプレート CheckForward のステートメント if (t.m != 0) t についても報告します。"forward" パラメーター t のメンバーにアクセスしているからです。

  • Polyspace はテンプレート NoninstantiatedTemplate をチェックしません。このテンプレートはコードで使用されていないからです。

チェック情報

グループ: 宣言子
カテゴリ: Required、Automated

バージョン履歴

R2021a で導入