Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to create a specialization-only function template?

Is there a better way to do the following?

#include <iostream>

template <typename T>
T Bar();

template <>
int Bar<int>() { return 3; }

// Potentially other specialisations

int main()
{
    std::cout << Bar<int>() << std::endl; // This should work
    std::cout << Bar<float>() << std::endl; // This should fail
}

The problem with this solution is that it fails at (understandably) link time with "undefined reference to float Bar<float>()" or the like. This can be confusing for other developers as they may suspect an implementation file is not being linked.

I do know another potential solution:

template <typename T>
T Bar() { BOOST_STATIC_ASSERT(sizeof(T) == 0); }

This causes a compiler error when Bar<float>() is requested, exactly what I want. However, I'm concerned that technically a compiler may reject this just as gcc rejects BOOST_STATIC_ASSERT(false) because it knows that it will fail regardless of the template parameter, since sizeof(T) can never be zero.

In summary, I want to know whether:

  1. There is another way to do this.
  2. I'm mistaken and BOOST_STATIC_ASSERT(sizeof(T)) actually can't fail without instantiation.
  3. The only way is to let this be a linker error as above.
like image 933
voltrevo Avatar asked Nov 29 '11 03:11

voltrevo


People also ask

What is function template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

How do I create a function template?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>( float original ); Template arguments may be omitted when the compiler can infer them.

What is explicit template specialization?

Explicit (full) specializationAllows customizing the template code for a given set of template arguments.

What is the specialty of a template function give example?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.


2 Answers

This could work:

template <typename T>
T Bar() {
  T::ERROR_invalid_template_argument_;
}

template <>
int Bar<int>() { return 3; }

You could also use the highest size possible if you're afraid of using 0:

  static_assert(sizeof(T) == -1, "No specialization");
like image 65
Pubby Avatar answered Oct 22 '22 23:10

Pubby


BOOST_STATIC_ASSERT(sizeof(T) == 0); isn't allowed to fail until the template is instantiated, so I would just do that one. You are correct that BOOST_STATIC_ASSERT(false); triggers each time.


The reason for this has to do with two-phase name lookup. This is, essentially, the following: when a template is compiled, it's compiled twice. The first time a compielr sees a template it compiles everything except the expressions dependent on template parameters, and the second compilation happens once the template parameter is known, compiling the instantiation fully.

This is why BOOST_STATIC_ASSERT(false); will fail always: nothing here is dependent and the assert is processed immediately, as if the function weren't a template at all. (Note that MSVC does not implement two-phase look-up, so this fails at instantiation, incorrectly.) Contrarily, because T is dependent (§14.6.2.1), BOOST_STATIC_ASSERT(sizeof(T) == 0); is dependent, and is not allowed to be checked until the template is instantiated. (Where upon it will always fail.)

If a compiler tries to be thoughtful and fail it ahead of time, it would be non-conforming. You're suppose to be able to rely on this stuff. That said, if fear gets the best of you it's trivial to really make it wait:

BOOST_STATIC_ASSERT(sizeof(typename T::please_use_specializations) == 0);

This is both guaranteed to fail, and impossible for a compiler to correctly "smartly" fail ahead of time.

like image 28
GManNickG Avatar answered Oct 22 '22 22:10

GManNickG