C++对重载函数的不明确调用

llycmphe  于 2023-03-05  发布在  其他
关注(0)|答案(4)|浏览(237)

我有下面的"安全" strncpy()代码--基本上,它的 Package 器自动为字符串缓冲区获取固定的数组大小,因此您不必做额外的工作来传入它们(这种方便性更安全,因为您不会意外地为固定数组缓冲区键入错误的大小)。

inline void MySafeStrncpy(char *strDest,size_t maxsize,const char *strSource)
{
    if(maxsize)
    {
        maxsize--;
        strncpy(strDest,strSource,maxsize);
        strDest[maxsize]=0;
    }
}

inline void MySafeStrncpy(char *strDest,size_t maxDestSize,
    const char *strSource, size_t maxSourceSize)
{
    size_t minSize=(maxDestSize<maxSourceSize) ? maxDestSize:maxSourceSize;
    MySafeStrncpy(strDest,minSize,strSource);
}

template <size_t size>
void MySafeStrncpy(char (&strDest)[size],const char *strSource)
{
    MySafeStrncpy(strDest,size,strSource);
}

template <size_t sizeDest,size_t sizeSource>
void MySafeStrncpy(char (&strDest)[sizeDest],
    const char (&strSource)[sizeSource])
{
    MySafeStrncpy(strDest,sizeDest,strSource,sizeSource);
}

template <size_t sizeSource>
void MySafeStrncpy(char *strDest,size_t maxDestSize,
    const char (&strSource)[sizeSource])
{
    MySafeStrncpy(strDest,maxDestSize,strSource,sizeSource);
}

使用此代码会导致Visual C++2008在编译时出错:

char threadname[16];
MySafeStrncpy(threadname,"MainThread");

error C2668: 'MySafeStrncpy' : ambiguous call to overloaded function
>        could be 'void MySafeStrncpy<16,11>(char (&)[16],const char (&)[11])'
>        or       'void MySafeStrncpy<16>(char (&)[16],const char *)'
>        while trying to match the argument list '(char [16], const char [11])'

我到底做错了什么?
在确定调用哪个模板函数时,编译器似乎无法确定字符串字面量"MainThread"应被视为const char *还是const char[11]
我希望它将字符串文本视为const char[11],并选择void MySafeStrncpy<16,11>(char (&)[16],const char (&)[11])变体,因为这是"最安全的"。
另外还有两个答案限制:1)我无法切换编译器(代码在其他编译器上编译)和2)公司不允许我使用外部模板库来获得解决方案。

nwwlzxa7

nwwlzxa71#

根据13.3.3.1.1,* 数组到指针的转换 * 具有 * 精确匹配 * 等级,因此此函数调用在标准规范中可能不明确。如果允许更改定义:

template <size_t size>
void MySafeStrncpy(char (&strDest)[size],const char *strSource)

致:

template <size_t size, class T>
void MySafeStrncpy(char (&strDest)[size], T strSource)

here,那么这可能是最简单的解决方法。

68de4m5k

68de4m5k2#

char-array/const-char-array和char-array/const-char-pointer的重载不能通过重载解析逻辑来区分(至少微软的逻辑是这样的--这段代码在GCC中编译得很好。不知道标准在这里说了什么。)。你需要用某种方式来区分它们,比如重命名数组函数或者添加一个伪参数。
一个优雅的解决方案是使用boost::enable_if和boost::is_array。

von4xj4u

von4xj4u3#

当你使用你的功能时:

MySafeStrncpy(threadname,"MainThread");

你没有在threadname和“MainThread”之间传递size_t参数,但是你已经在函数定义中定义了。
应该是这样:

MySafeStrncpy(threadname, sizeof threadname, "MainThread");

如果你不想传递参数,那么在你的函数定义中设置它为默认值。

mzillmmw

mzillmmw4#

对于char指针和char数组,不能有两个函数重载,但可以有两个类模板专门化:

template<typename StringConstant>
class Impl
{
    auto operator()(const StringConstant& str) = delete;
}

template<typename Elem>
[[deprecated("Passing char pointer without length is unsafe")]]
class Impl<const Elem*>
{
    auto operator()(const Elem* str) -> ...
    { ... }
}

template<typename Elem, std::size_t Size>
class Impl<const Elem[Size]>
{
    auto operator()(const Elem str[Size]) -> ...
    {
        // Remember that length of str is Size - 1 (don't include null character)
        ...
    }
}

template<typename StringConstant>
auto func(const StringConstant& str) -> ...
{
    return Impl<StringConstant>()(str);
}

// Need function overload for C arrays.
// When used as rvalue expressions, arrays decay to pointers to the first element.
// See https://stackoverflow.com/a/9128891/2279059
template<typename Elem, std::size_t Size>
auto func(const Elem(&str)[Size]) -> ...
{
    return Impl<Elem[Size]>()(str);
}

请注意,除了向后兼容性之外,你不需要这些东西。不要使用常量C字符数组,而使用static const字符串即可。在任何地方接受原始字符指针的唯一原因是为了与旧代码或第三方库兼容。如果你需要函数接受“任何类型的字符串常量”,最好使用std::basic_string_view

相关问题