Re: Meaning of terms "subexpression" and "constant expression"
On 1 Feb, 01:43, James Kanze <james.ka...@gmail.com> wrote:
On Jan 29, 4:39 pm, "Johannes Schaub (litb)"
<schaub.johan...@googlemail.com> wrote:
Nikolay Ivchenkov wrote:
Consider the following example:
#include <iostream>
template <void (*pf)()>
struct X
{
template <void (*)()>
struct Y;
static void instantiate() { (void)m; }
typedef Y<&X::instantiate> Inst;
X() { pf(); }
static X m;
};
template <void (*pf)()>
X<pf> X<pf>::m;
void f()
{
std::cout << "f()\n";
}
int main()
{
sizeof X<&f>();
}
According to N3225 - 3.2/2,
An expression is potentially evaluated unless it is an unevaluated
operand (Clause 5) or a subexpression thereof.
Can the expression f in sizeof X<&f>() be considered as subexpression
of X<&f>()? Is the expression f potentially evaluated and is the
function f odr-used?
I agree, this smells. I can't find what in the spec requires "f" to be
defined either.
The standard clearly says that a definition of f isn't necessary
here.
I don't think so. The expression X::instantiate is potentially
evaluated (it is not an unevaluated operand nor a subexpression
thereof). Thus, X<&f>::instantiate is odr-used and it is implicitly
instantiated. X<&f>::instantiate refers to X<&f>::m as to potentially
evaluated expression, thus X<&f>::m is odr-used, it is implicitly
instantiated, and the constructor X<&f>::X() must be instantiated to
perform initialization of that object. This constructor calls a
function pointed to by pf, so pf shall refer to some existing
function.
If there is no definition for f, the behavior is undefined anyway
(regardless of whether ODR requires the definition to exist). However,
I can replace simple function f with a function template f:
#include <iostream>
template <void (*pf)()>
struct X
{
template <void (*)()>
struct Y;
static void instantiate() { (void)m; }
typedef Y<&X::instantiate> Inst;
X() { pf(); }
static X m;
};
template <void (*pf)()>
X<pf> X<pf>::m;
template <class T>
void f()
{
std::cout << "f()\n";
}
int main()
{
sizeof X<&f<void>>();
}
Now ODR determines whether f<void> must be implicitly instantiated. If
f<void> is not instantiated, we have evaluation of undefined function.
The effect of such evaluation is not defined by the C++0x rules. If
f<void> is instantiated, we have well-defined program.
I think that a template argument should be potentially evaluated
regardless of whether it is a lexical part of an unevaluated operand.
Let me show another example:
template <int N>
struct X
{
typedef char type[N];
};
template <int N>
constexpr int f()
{
return N;
}
int n = sizeof(X<f<2>()>::type);
It is impossible to determine the result of the sizeof expression
without evaluation of f<2>(). If so, there should be rules that would
clearly require f<2> to be implicitly instantiated. I don't see such
rules in the latest working draft.
At least one compiler accepts the code even if the
definition of f is replaced by a declaration. And off hand,
I can't see why not (even if both g++ and VC++ reject it).
Missing function definition is not required to be diagnosed. Such
violation of ODR (if it takes place) implies undefined behavior, so we
can get any results.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]