给出以下代码:
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <source_location>
template<std::size_t N>
struct StringWrapper {
// consteval to force only compile-time strings
consteval StringWrapper(const char (&format_string)[N], std::source_location source_location = std::source_location::current())
: SourceInfo{ source_location } {
std::copy(std::begin(format_string), std::end(format_string), std::begin(FormatString));
}
char FormatString[N]{};
// This here to motivate not using StringWrapper as non-type template argument
std::source_location SourceInfo{};
};
// class-template-argument-deduction is not necessary here, see the first case in main
// variadic template, thus putting std::source_location at the end is not an option
template<std::size_t N, class... Args>
void log(StringWrapper<N> format_string, Args&&... args);
int main()
{
log(StringWrapper{ "This {}, explicitly instantiating, but deducing the parameter" }, "works");
log("This {}, could not match 'StringWrapper<N>' against 'const char *'", "fails");
}
有什么可能的解决方法可以解决此问题而不需要对调用站点进行更改?
一种可能性是使用 std::string_view
,但是这不会让我访问 N
作为执行 log
中的常量表达式因此对于我来说这不是一个选择。
另一种可能是直接取 const char (&)[N]
,但是我失去了 std::source_location
这也不是一个选择。
我明白为什么重载解析会倾向于采用 const char*
的函数一个带有 const char (&)[N]
的函数,但是我不明白为什么“StringWrapper”甚至没有尝试与“const char (&)[N]”匹配。
最佳答案
您可以使用类模板参数推导来执行此操作(将 log
更改为对象构造函数而不是普通函数)
template<std::size_t N, class... Args>
struct log{
log(StringWrapper<N> src, Args&&... args){}
};
template<std::size_t N, class... Args>
log(const char(&)[N],Args&&...) -> log<N,Args...>;
template<std::size_t N, class... Args>
log(StringWrapper<N>,Args&&...) -> log<N,Args...>;
关于c++ - 由于字符数组到指针衰减而无法推导非类型模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74164953/