これはコンパイルされませんfunction_type_deducer([](){}).describe_me();
function_type_deducer
テンプレじゃなくても大丈夫。:) 非キャプチャ ラムダ (空[]
) は暗黙的に関数ポインターに変換可能です。残念ながら、一部のテンプレート引数推定では、暗黙的な変換が考慮されていません。詳細については、この質問を参照してください (コメントが示すように、私の答えが完全に正しいわけではないことに注意してください)。
y は文字列 & を取り、x は文字列を取るため、x と y の間に小さな違いがあることに気付きません。
typeid
この単純なテストコードが示すように、これは関数の問題ではなく、 の問題です。
template<class T>
void x(void(T)){
T v;
(void)v;
}
void f1(int){}
void f2(int&){}
int main(){
x(f1);
x(f2);
}
Ideone での実例。出力:
エラー: 'v' は参照として宣言されていますが、初期化されていません
簡単な修正は、タグのディスパッチを使用することです。
#include <type_traits> // is_reference
#include <iostream>
#include <typeinfo>
template<class T>
void print_name(std::true_type){
std::cout << "reference to " << typeid(T).name();
}
template<class T>
void print_name(std::false_type){
std::cout << typeid(T).name();
}
template<class T>
void print_name(){
print_name(typename std::is_reference<T>::type());
}
print_name<NextArg>()
の代わりに呼び出しますtypeid(NextArg).name()
。
私は車輪を再発明しましたか?
はい、そうではありません。Boost.Functionは、すべての引数 (argN_type
スタイル) の型定義と、その数の静的定数arity
を提供します。ただし、これらの typedef に一般的に簡単にアクセスすることはできません。存在しないものに誤ってアクセスしないようにするための回り道が必要です。アイデアは最もtuple
うまく機能しますが、より良い方法で書くことができます。これは、私がかつて書いたものの修正版です。
#include <tuple>
#include <type_traits>
#include <iostream>
#include <typeinfo>
namespace detail{
template<class T>
std::ostream& print_name(std::ostream& os);
template<class T>
std::ostream& print_pointer(std::ostream& os, std::true_type){
typedef typename std::remove_pointer<T>:: type np_type;
os << "pointer to ";
return print_name<np_type>(os);
}
template<class T>
std::ostream& print_pointer(std::ostream& os, std::false_type){
return os << typeid(T).name();
}
template<class T>
std::ostream& print_name(std::ostream& os, std::true_type){
return os << "reference to " << typeid(T).name();
}
template<class T>
std::ostream& print_name(std::ostream& os, std::false_type){
return print_pointer<T>(os, typename std::is_pointer<T>::type());
}
template<class T>
std::ostream& print_name(std::ostream& os){
return print_name<T>(os, typename std::is_reference<T>::type());
}
// to workaround partial function specialization
template<unsigned> struct int2type{};
template<class Tuple, unsigned I>
std::ostream& print_types(std::ostream& os, int2type<I>){
typedef typename std::tuple_element<I,Tuple>::type type;
print_types<Tuple>(os, int2type<I-1>()); // left-folding
os << ", ";
return print_name<type>(os);
}
template<class Tuple>
std::ostream& print_types(std::ostream& os, int2type<0>){
typedef typename std::tuple_element<0,Tuple>::type type;
return print_name<type>(os);
}
} // detail::
template<class R, class... Args>
struct function_info{
typedef R result_type;
typedef std::tuple<Args...> argument_tuple;
static unsigned const arity = sizeof...(Args);
void describe_me(std::ostream& os = std::cout) const{
using namespace detail;
os << "I return '"; print_name<result_type>(os);
os << "' and I take '" << arity << "' arguments. They are: \n\t'";
print_types<argument_tuple>(os, int2type<arity-1>()) << "'\n";
}
};
Ideone での実例。出力:
main: I return 'i' and I take '2' arguments. They are:
'i, pointer to pointer to c'
x: I return 'Ss' and I take '3' arguments. They are:
'i, Ss, c'
y: I return 'Ss' and I take '3' arguments. They are:
'i, reference to Ss, c'