避免在函数调用上缩小类型转换

时间:2014-11-10 16:23:20

标签: c++11

假设你想在调用函数时避免缩小

void foo(char c) { /* ... */ }

foo(4); // get a compilation error here

2 个答案:

答案 0 :(得分:1)

您可以在具有

的T上使用类模板

1)不同类型X上的模板构造函数,当参数不是T时尝试实例化类

2)一个带有T作为参数的构造函数,用于处理您使用确切类型实例化类的情况

#include <iostream>

// g++-4.9 -Werror=narrowing -std=c++11 main2.cc
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55783

template <typename T>
struct no_narrowing
{
    using type = T;

    // this template constructor lets you try to
    // instantiate a no_narrowing using a different
    // type. if Narrowing would take place 
    // value{ val } takes care of it
    template <typename X>
        no_narrowing(X val) : value{val} {}

    // if type is exactly T we use this
    no_narrowing(type val) : value{val} {}

    operator type() const { return value;}

    type value;
};

template <typename T>
using nn = no_narrowing<T>;


void print(nn<char> v)
{
    std::cout << v << std::endl;
}

int main(int argc, char *argv[])
{
    int i = 2;

    print('d'); 
    print(i); // this will not compile

    return 0;
}

答案 1 :(得分:1)

您可以定义目标函数和转发模板重载,以尝试非缩小转换为目标类型( DEMO ):

void foo(char) {}
template <typename T>
void foo(T&& t) { foo(char{std::forward<T>(t)}); }

foo('a');
// foo(4);    // ill-formed
foo({4});
// foo(0);    // ill-formed
foo({0}); 
// foo(u'a'); // ill-formed
foo({u'a'});
int i = 2;
// foo(i);    // ill-formed
// foo({i});  // ill-formed

这有一个很好的优势,客户端可以通过传递一个braced-init-list强制转换。由于braced-init-list阻止了模板推导,因此只能通过重载决策来选择目标函数。即使例如foo(4)与模板重载相匹配且格式错误 - 由于int通常无法缩小,因此char无法转换为foo({4}) - 4格式正确char可以转换为{{1}}而不会缩小。