1

I could find some questions asking about why I cannot specialize member functions:

  1. Why can't you partially specialize a class member function?
  2. Partially specializing member-function implementations
  3. why cannot partially specialize a member function, in c++ template

But why does the C++ specification not allow partial specialization of template functions, when they are not necessarily members of a class?

#include <array>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template< int PathIndex, int PathLength >
constexpr const int findlastslash(const char (&path)[PathLength])
{
    constexpr const int end = PathLength - PathIndex;
    return (PathIndex >= 0 && path[end] != '/' && path[end] != '\\') 
            ? findlastslash< PathIndex - 1, PathLength >( path ) : ( end + 1 );
}

template< int PathLength >
constexpr const int findlastslash< 1, PathLength >(const char (&path)[PathLength]);

template< int PathLength >
constexpr const int startfindlastslash(const char (&path)[PathLength]) {
    return findlastslash< PathLength >( path );
}

int main(int argc, char const *argv[])
{
    STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 17 );
}
$ g++ -o main.exe --std=c++14 test_debugger.cpp
test_debugger.cpp:12:82: error: non-class, non-variable partial specialization ‘findlastslash<1, PathLength>’ is not allowed
 constexpr const int findlastslash< 1, PathLength >(const char (&path)[PathLength]);
                                                                                  ^
test_debugger.cpp: In instantiation of ‘constexpr const int startfindlastslash(const char (&)[PathLength]) [with int PathLength = 30]’:
test_debugger.cpp:21:5:   required from here
test_debugger.cpp:16:39: error: call of overloaded ‘findlastslash<30>(const char [30])’ is ambiguous
     return findlastslash< PathLength >( path );
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
test_debugger.cpp:5:21: note: candidate: constexpr const int findlastslash(const char (&)[PathLength]) [with int PathIndex = 30; int PathLength = 30]
 constexpr const int findlastslash(const char (&path)[PathLength])
                     ^~~~~~~~~~~~~
test_debugger.cpp:12:21: note: candidate: constexpr const int findlastslash(const char (&)[PathLength]) [with int PathLength = 30]
 constexpr const int findlastslash< 1, PathLength >(const char (&path)[PathLength]);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test_debugger.cpp: In function ‘int main(int, const char**)’:
test_debugger.cpp:2:28: error: non-constant condition for static assertion
 #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
                            ^
test_debugger.cpp:21:5: note: in expansion of macro ‘STATIC_ASSERT’
     STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 17 );
     ^~~~~~~~~~~~~
test_debugger.cpp:21:5:   in constexpr expansion of ‘startfindlastslash<30>("cppdebugger/test_debugger.cpp")’
test_debugger.cpp:2:28: error: constexpr call flows off the end of the function
 #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
                            ^
test_debugger.cpp:21:5: note: in expansion of macro ‘STATIC_ASSERT’
     STATIC_ASSERT( startfindlastslash( "cppdebugger/test_debugger.cpp" ) == 17 );

While free function template partial specializations are not allowed, we can do an equivalent using class template partial specialization. A correct version of this example using class partial template specialization can be found on: How to stop template recursion while using parameter deduction?

JaMiT
  • 14,422
  • 4
  • 15
  • 31
Evandro Coan
  • 8,560
  • 11
  • 83
  • 144
  • 5
    Because functions are subject of overload resolution and so you can have several function templates with same name that accept different arguments. Partial specializations just complicate it without any gain. – Öö Tiib Dec 24 '19 at 21:41
  • 1
    "loose functions" --> called "free functions" most of the time AFAIK – Daniel Jour Dec 24 '19 at 22:52
  • What sort of answer are you looking for? A simple "because that's what the standard says" answer? Something that quotes the part of the standard that says it? A reason why the standard says it? Something else? – JaMiT Dec 25 '19 at 00:33
  • @JaMiT, Just something that makes sense, i.e., a reasonable motive. For example, the impression I got was that the standard did not allowed it just because they said so or felt like (without any background/base). But as **`@ÖöTiib`** said, it seems it has a reason, the implementation or either will be too complex, or there is a direct conflict with functions overloading. This itself can be an answer, but if you can show an example of how this can be a problem, it would be awesome. – Evandro Coan Dec 25 '19 at 01:04
  • @user So reasons for the restriction, not necessarily the reasons considered by the standards committee. Hmm... may I suggest changing *"why I cannot partially specialize a loose (free) functions?"* to something more like *"what justifications can be given for the C++ specification not allowing partial specialization of function templates"*? (Sorry, I don't have a good answer.) – JaMiT Dec 25 '19 at 02:30
  • Essentially most if not all reasons you have found for member function should apply to free function and I would say even more given overloading which cause additional surprises depending if the partial specialization have been seen or not. Also there is an easy workaround as you can define a class and call it from the function. A few extra lines of code instead of make the language even more complicated. – Phil1970 Dec 25 '19 at 02:40
  • 1
    Many of those questions link to this explanation: http://www.gotw.ca/publications/mill17.htm – parktomatomi Dec 26 '19 at 04:51

0 Answers0