1

Take the following peice of c++ code, which compiles fine (gcc 10.1.0) : -

#include <iostream>
#include <string>
#include <functional>

template <class T = std::string>
void foo(T src, std::function<void(T&& t)> completionFn)
{
    completionFn(std::move(src));
}

int main(int argc, char *argv[])
{
    foo<std::string>("hello", [] (auto && t) {
        std::cout << t << std::endl;
    });

    return 0;
}

If I modify the main function to remove the template parameter in the call to "foo", it no longer compiles even though I have a default template parameter, and I cannot work out why.

int main(int argc, char *argv[])
{
    foo<>("hello", [] (auto && t) {
        std::cout << t << std::endl;
    });

    return 0;
}

I am probably missing something obvious.

Here is the compiler output : -

src/scanner_test.cpp: In function ‘int main(int, char**)’:
src/scanner_test.cpp:19:6: error: no matching function for call to ‘foo(const char [6], main(int, char**)::<lambda(auto:11&&)>)’
   19 |     });
      |      ^
src/scanner_test.cpp:10:6: note: candidate: ‘template<class T> void foo(T, std::function<void(T&&)>)’
   10 | void foo(T src, std::function<void(T&& t)> completionFn)
      |      ^~~
src/scanner_test.cpp:10:6: note:   template argument deduction/substitution failed:
src/scanner_test.cpp:19:6: note:   ‘main(int, char**)::<lambda(auto:11&&)>’ is not derived from ‘std::function<void(T&&)>’
   19 |     });

What am I missing? Thanks! Apologies if it's a silly question.

1 Answer 1

3

The default template parameter is only used if the template CANNOT be determined from context. In the context given foo<>("hello", ...) the template T is determined to be const char [6] (as given in the error message). For functions this will always be the case for template parameters that relate to real parameters in the function.

The solution you maybe looking for is:

#include <iostream>
#include <string>
#include <functional>

template <class T>
void foo(T src, std::function<void(std::string&& t)> completionFn)
{
    //NOTE cast here to std::string, ensures we always have an std::string
    completionFn(std::move((std::string&)src));
}

int main(int argc, char *argv[])
{
    foo("hello", [] (std::string&& t) {
        std::cout << t << std::endl;
    });

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

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.