Please consider the example below. The class template Sample
attempts to initialize reference members using a member function of a template parameter, expected to return an appropriate reference.
class Inner
{
public:
Inner() : x_{1}
{
}
private:
int x_;
};
class Outer
{
public:
Inner& GetInner()
{
return inner_;
}
private:
Inner inner_;
};
template<typename T>
class Sample
{
public:
Sample(T& outer) :
innerOk_{static_cast<Inner&>(outer.GetInner())},
innerFail_{outer.GetInner()} // ICC fails with "error: initial value of reference to non-const must be an lvalue"
{
}
private:
Inner& innerOk_;
Inner& innerFail_;
};
int main(int argc, char* argv[])
{
Outer outer;
Sample<Outer> s{outer};
return 0;
}
Of course, before seeing an actual parameter for T
, there is no way for a compiler to tell whether the initialization is valid, or whether the type returned by the function would not be suitable. As it also couldn't tell whether T
is going to have such a function or whether it's going to return anything at all.
Following workarounds make the code pass:
- Use a
static_cast
to confirm the expected type, as withinnerOk_
in the example. - Use
()
-initialization instead of{}
.
Is ICC (19.0.1) right in performing that check so early and rejecting the direct initialization? GCC accepts both.