让c++编译器显示一个类型可以转换成什么类型

Getting the C++ compiler to reveal what a type can be converted to

本文关键字:类型 转换 什么 一个 编译器 c++ 显示      更新时间:2023-10-16

下面是一个有缺陷的(和简化的)模板函数,它期望在一个模板参数上工作,该参数可以转换为预定义数量的类型之一。

碰巧是两种类型,但可能更多。

void do_something_type_specific( const int &unused ) { std::cout << 'i'; }
void do_something_type_specific( const std::string &unused ) { std::cout << 's'; }
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    do_something_type_specific( *begin );
    // Perhaps more code...
}

这恰好在我的环境中产生了期望的结果。如果*Iterator生成的类型恰好可以转换为其中一个选项,则模板实例将成功编译。

然而,这段代码不必要地要求执行转换,尽管unused未使用,但当begin == end时仍然存在UB。

如何在c++ 03中实现这个行为而不出现这些问题?

begin == end时,您可以尝试使用std::iterator_traits<>而不是解引用导致未定义行为的迭代器。例如:

#include <iterator>
#include <string>
#include <cstdio>
void do_something_type_specific(std::string const&) { printf("%sn", __PRETTY_FUNCTION__); }
void do_something_type_specific(int const&) { printf("%sn", __PRETTY_FUNCTION__); }
template<class T>
struct ProduceValue
{
    static T value;
};
template<class T>
T ProduceValue<T>::value;
// Specializations for types that can't be default constructed or must be initialized.
template<>
char* ProduceValue<char*>::value = "";
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific(ProduceValue<value_type>::value);
}
int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);
    long* q = 0;
    perform_work_on_a_range(q, q);
}
输出:

void do_something_type_specific(const string&)
void do_something_type_specific(const int&)

唯一的不便之处在于ProduceValue<T>必须专门化用于不能默认构造或由于其他原因必须初始化的类型(如char*)。

您可以使用boost::is_convertible元函数来确定类型T是否可以转换为其他类型u

其次,对于begin == end,只需插入运行时检查。

问题中的问题代码试图利用模板参数函数参数的特性。

函数形参允许类型转换,但需要类型的实例化。模板形参不需要实例化,但也不需要执行类型转换。

下面的模式使用Boost的enable_ifis_convertible来允许编译器选择模板函数,就好像模板参数支持与函数参数相同的类型转换规则一样。(感谢@dhavenith的建议)
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
// enable_if_c makes the return type either void or a Substitution Failure.
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type
do_something_type_specific()
{
  std::cout << 'i';
}
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type
do_something_type_specific()
{
  std::cout << 's';
}
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    // This code is from @MaximYegorushkin's answer.  Vote him up :)
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific<value_type>();
    // Perhaps more code...
}

这已经通过@MaximYegorushkin的示例main进行了验证。

int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);
    long* q = 0;
    perform_work_on_a_range(q, q);
}
输出:

si

您可能想要这样做:

template <typename T>
void do_something_type_specific() {}
template <>
void do_something_type_specific<int>() {...}
template <typename Iterator>
void perform_work_on_a_range(Iterator begin, Iterator end) {
    do_something_type_specific<typename Iterator::value_type>();
}