-2
template<typename T>
class A { };

U x;
A<U> ... // OK
A<x> ... // ERROR

If we can, then how do we make a specialization of class A whose argument is an object of any type?

AJ Tan
  • 193
  • 7
  • 4
    `A` expects a type for an argument. `x` is not a type. What are you ultimately trying to achieve here? Looks like an [XY problem](http://xyproblem.info/). – Igor Tandetnik Aug 15 '20 at 14:59
  • 2
    We can not instantiate a template with an argument which is unknown at compile time. – chi Aug 15 '20 at 14:59
  • 3
    There are [non-type template parameters](https://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter), but a parameter can't be both 'type' and 'non-type' at the same time. Even if we ignore that, `U x;` wouldn't work as a template argument because it's not `constexpr`. What's your ultimate goal? – HolyBlackCat Aug 15 '20 at 15:01
  • For template specialization, read [full template specialization](https://en.cppreference.com/w/cpp/language/template_specialization) and [partial template specialization](https://en.cppreference.com/w/cpp/language/partial_specialization). – masoud Aug 15 '20 at 15:01
  • ...but specializations won't help you here. – HolyBlackCat Aug 15 '20 at 15:02
  • You have to pass through `decltype()`: `A` – max66 Aug 15 '20 at 15:05
  • Just rewrite it to *"A"*, as max66 pointed out. *"x"* is a stored variable, whereas *"U"* is a data type. By the way, you've already made the specialization of any type in your first declaration. If you look for further specialization, that'll be `"template<> class A{public:explicit A(void){cout << "the bool constructor";};};"` – Alex TheBN Aug 15 '20 at 15:22
  • Do you really mean "specialization"? Your code suggests you mean "instantiation". (A specialization is another template whose parameters are specialized. An instantiation is the actual use of a template, creating a specific type from the template blueprint.) – JaMiT Aug 15 '20 at 17:16
  • Thank you all for sharing some info. I, however, used another method to solve my problem. Perhaps using class templates isn't the way to go. My apologies for all the trouble and for abstracting my intentions. I'm still quite new to template specialization and I appreciate all your efforts. – AJ Tan Aug 16 '20 at 02:24

1 Answers1

1

Before considering "argument is an object of any type", we should first understand the limitations for "argument is an object". (See also How to use an object instance as template argument?)

A clarification before getting into this: What's the difference between an argument and a parameter? A template parameter is the placeholder used in a definition, such as this question's <typename T>. An argument is the replacement provided when the definition is used, such as this question's <U>.

Objects as template parameters

Technically, a template parameter that is neither a type nor a template cannot be an object of class type, but it can be a (lvalue) reference to an object. C++20 relaxes this a bit but not all the way to "any type", so I'll ignore this caveat for now.

In practice, converting a parameter from being an object to being a reference is just a bit of syntax juggling. Still, there is an important bit of semantics to this: different objects produce different template instantiations, even if you believe the objects to be "equal". If you ignore this point, you might needlessly bloat your code. Are you sure this is consistent with your goal?

Objects as template arguments

A template argument that is neither a type nor a template must be a compile-time constant. This is a refrain that is commonly heard when discussing templates. However, it has a perhaps surprising implication when dealing with references. In order for an object reference to be a compile-time constant expression, it must refer to an object with static storage duration. That is, the object must be:

  • declared at namespace scope,
  • declared with static, or
  • declared with extern.

This should make sense if you think about it. A reference needs the address of the object to which it refers. Only an object that is allocated when the program begins has an address that is known at compile time. The address of an object local to a function depends on where in the call stack that particular function call lies, which is a run-time quality.

While a template parameter could be a reference to an object of any type, it is not true that any object of any type could be used as the corresponding argument.

Template parameter of any type

Subject to the above restrictions, allowing an object of any type is just a matter of allowing an object and allowing a type. There are two things that can vary. One of these can hide behind the "auto" keyword.

template<const auto & Object>
class A {};

If you want to be more restrictive about which types are accepted (such as objects of class type, as opposed to objects of fundamental type), there are various type properties that can be used with SFINAE.

Example:

template<const auto & Object>
class A {};

// A class for demonstration purposes
class U {};

// A global variable (declared at namespace scope)
U x;

int main()
{
    // A static variable
    static U y;

    // A local variable
    U z;

    // Try to instantiate the template
    A<x> compiles;
    A<y> fine;
    //A<z> fails;

    // Suppress unused variable warnings
    (void) compiles;
    (void) fine;
    (void) z;
}

Now that you know you could do this, stop to think if you should. You probably should not. Maybe it's just a bit of over-engineering? Trying to be "cool"? How bad could it get?

JaMiT
  • 14,422
  • 4
  • 15
  • 31