12

Consider the following code:

template <unsigned int N>
struct myclass
{
    unsigned int f() {return N;}
    unsigned int g() {static_assert(N > 0, ""); return N-1;}
};

Question: Do I have the guarantee that the following code will compile:

myclass<0> c;
c.f();

But the following will not:

myclass<0> c;
c.f();
c.g();
3
  • Sure, the first does not instantiate 'g' (besides, the private nature of the functions) Commented Jun 11, 2015 at 18:02
  • @DieterLücking Changed class to struct. Commented Jun 11, 2015 at 18:03
  • @Vincent f() should be made public as well as g() Commented Jun 11, 2015 at 18:08

3 Answers 3

11

Yes, you have that guarantee. From [temp.inst]/11, emphasis mine:

An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation.

If you don't call g(), it doesn't require instantiation, so there should be no issues calling myclass<0>{}.f().

This is the same guarantee that lets you use std::vector and std::map with types that aren't default constructible as long as you don't do things like call resize() and operator[], respectively.

A followup, as Jarod42 points out, is that explicitly instantiating myclass<0> will produce the assert because, from [temp.explicit]/8:

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes and members that are templates) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.

The exceptions don't apply here.

Sign up to request clarification or add additional context in comments.

4 Comments

Note that explicitly instantiate myclass<0> (template struct myclass<0>;) will produce the assert.
Pedantic: "you have that guarantee" modulo the usual disclaimer that the standard only requires a diagnostic message when a static assertion fires and does not require the compilation to fail.
@Barry: do you have an example of how I can make compilation fails using resize() on a vector for a type that is not default constructible?
@Vincent Just call resize(n) on it for any n?
0

Use a template specialization:

template <unsigned N>
struct myclass
{
    unsigned f () { return N; }
    unsigned g () { return N-1; }
};

template <>
struct myclass <0>
{
    unsigned f () { return 0; }
};

2 Comments

This is the right way if you need explicit instantiation, but also a pain because all the other members need to be duplicated.
@BenVoigt True, but I think in practice, class templates that are designed to enforce constraints do not (and should not) contain much else.
-2

If you wish to disable a function at compiler time, you should use enable_if instead of static_assert

template<unsigned int N>
struct Foo {
    unsigned int f() {}
    enable_if_t<(N > 0), unsigned int> g() {}
};

Foo<0> t{};
t.f(); /// this is okay and will compile
// t.g() if I uncomment this line, it will not compile anymore.

2 Comments

Not necessarily. The usage of enable_if above is incorrect for one thing, as you have to be in a templated context for it to work. Even turning that into a templated member function, enable_if is really for adding/removing something to the candidate set as opposed to always wanting a hard error when attempting to invoke.
This will not compile, your enable if isn't in a context in which SFINAE applies, so it's simply a hard failure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.