Search code examples
c++c++17constructor-overloadingctaddeduction-guide

Deduction guide based on number of parameters passed to constructor


Here's something I'm trying that doesn't seem to work: I want to toggle a compile time switch based on how a class object is instantiated. If there's just one constructor argument, the LengthOpt should equal to false, otherwise to true (my implementation has more constructors where the switch should default to true.

I tried to create a deduction guide, but apparently it doesn't work if the template argument doesn't show up as a constructor argument (which is a real downer). Does anyone know a not-too-verbose solution to this problem?

Code:

#include <cstring>
#include <iostream>

const char* str = "some input string";


template <bool LengthOpt>
class some_class
{
public:
    some_class(const char*) {
        std::cout << std::boolalpha << LengthOpt << std::endl;
    }
    some_class(const char*, size_t len) {
        std::cout << std::boolalpha << LengthOpt << std::endl;
    }
};

template <bool LengthOpt> some_class(const char*) -> some_class<false>;
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;

int main()
{
    some_class A(str);
    some_class B(str, strlen(str));
}

Errors:

<source>:19:27: error: deduction guide template contains a template parameter that cannot be deduced
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
<source>:19:16: note: non-deducible template parameter 'LengthOpt'
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
               ^
<source>:20:27: error: deduction guide template contains a template parameter that cannot be deduced
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:20:16: note: non-deducible template parameter 'LengthOpt'
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
               ^
<source>:24:16: error: no viable constructor or deduction guide for deduction of template arguments of 'some_class'
    some_class A(str);
               ^
<source>:11:5: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
    some_class(const char*) {
    ^
<source>:19:27: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
<source>:8:7: note: candidate template ignored: could not match 'some_class<LengthOpt>' against 'const char *'
class some_class
      ^
<source>:14:5: note: candidate function template not viable: requires 2 arguments, but 1 was provided
    some_class(const char*, size_t len) {
    ^
<source>:20:27: note: candidate function template not viable: requires 2 arguments, but 1 was provided
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:25:16: error: no viable constructor or deduction guide for deduction of template arguments of 'some_class'
    some_class B(str, strlen(str));
               ^
<source>:14:5: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
    some_class(const char*, size_t len) {
    ^
<source>:20:27: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:11:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    some_class(const char*) {
    ^
<source>:8:7: note: candidate function template not viable: requires 1 argument, but 2 were provided
class some_class
      ^
<source>:19:27: note: candidate function template not viable: requires 1 argument, but 2 were provided
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
4 errors generated.
ASM generation compiler returned: 1
<source>:19:27: error: deduction guide template contains a template parameter that cannot be deduced
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
<source>:19:16: note: non-deducible template parameter 'LengthOpt'
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
               ^
<source>:20:27: error: deduction guide template contains a template parameter that cannot be deduced
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:20:16: note: non-deducible template parameter 'LengthOpt'
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
               ^
<source>:24:16: error: no viable constructor or deduction guide for deduction of template arguments of 'some_class'
    some_class A(str);
               ^
<source>:11:5: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
    some_class(const char*) {
    ^
<source>:19:27: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
<source>:8:7: note: candidate template ignored: could not match 'some_class<LengthOpt>' against 'const char *'
class some_class
      ^
<source>:14:5: note: candidate function template not viable: requires 2 arguments, but 1 was provided
    some_class(const char*, size_t len) {
    ^
<source>:20:27: note: candidate function template not viable: requires 2 arguments, but 1 was provided
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:25:16: error: no viable constructor or deduction guide for deduction of template arguments of 'some_class'
    some_class B(str, strlen(str));
               ^
<source>:14:5: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
    some_class(const char*, size_t len) {
    ^
<source>:20:27: note: candidate template ignored: couldn't infer template argument 'LengthOpt'
template <bool LengthOpt> some_class(const char*, size_t) -> some_class<true>;
                          ^
<source>:11:5: note: candidate function template not viable: requires 1 argument, but 2 were provided
    some_class(const char*) {
    ^
<source>:8:7: note: candidate function template not viable: requires 1 argument, but 2 were provided
class some_class
      ^
<source>:19:27: note: candidate function template not viable: requires 1 argument, but 2 were provided
template <bool LengthOpt> some_class(const char*) -> some_class<false>;
                          ^
4 errors generated.
Execution build compiler returned: 1

Solution

  • You don't need a template parameter, just do:

    some_class(const char *) -> some_class<false>;
    some_class(const char *, size_t) -> some_class<true>;
    

    Deduction guides are like functions, but all their template parameters must be deducible from their function parameters.

    template <bool LengthOpt> some_class(const char*) -> ... turns into something like template <bool LengthOpt> void foo(const char*), where LengthOpt is non-deducible.